Build tree couples
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
import { APIClient } from "./ApiClient";
 | 
			
		||||
import { DateValue, Member } from "./MemberApi";
 | 
			
		||||
import { ServerApi } from "./ServerApi";
 | 
			
		||||
 | 
			
		||||
interface CoupleApiInterface {
 | 
			
		||||
  id: number;
 | 
			
		||||
@@ -99,6 +100,10 @@ export class Couple implements CoupleApiInterface {
 | 
			
		||||
      day: this.divorce_day,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  otherPersonID(id: number): number | undefined {
 | 
			
		||||
    return id === this.wife ? this.husband : this.wife;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CouplesList {
 | 
			
		||||
@@ -137,6 +142,10 @@ export class CouplesList {
 | 
			
		||||
  getAllOf(m: Member): Couple[] {
 | 
			
		||||
    return this.filter((c) => c.husband === m.id || c.wife === m.id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFirstMariedOf(m: Member): Couple | undefined {
 | 
			
		||||
    return this.getAllOf(m).find((c) => (c.state = "M"));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CoupleApi {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import { useParams } from "react-router-dom";
 | 
			
		||||
import { useFamily } from "../../widgets/BaseFamilyRoute";
 | 
			
		||||
import ClearIcon from "@mui/icons-material/Clear";
 | 
			
		||||
import {
 | 
			
		||||
  Alert,
 | 
			
		||||
  FormControl,
 | 
			
		||||
@@ -12,10 +11,15 @@ import {
 | 
			
		||||
  Tab,
 | 
			
		||||
  Tabs,
 | 
			
		||||
} from "@mui/material";
 | 
			
		||||
import { MemberItem } from "../../widgets/MemberItem";
 | 
			
		||||
import ClearIcon from "@mui/icons-material/Clear";
 | 
			
		||||
import { RouterLink } from "../../widgets/RouterLink";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { useParams } from "react-router-dom";
 | 
			
		||||
import {
 | 
			
		||||
  buildAscendingTree,
 | 
			
		||||
  buildDescendingTree,
 | 
			
		||||
} from "../../utils/family_tree";
 | 
			
		||||
import { useFamily } from "../../widgets/BaseFamilyRoute";
 | 
			
		||||
import { MemberItem } from "../../widgets/MemberItem";
 | 
			
		||||
import { RouterLink } from "../../widgets/RouterLink";
 | 
			
		||||
 | 
			
		||||
enum CurrTab {
 | 
			
		||||
  BasicTree,
 | 
			
		||||
@@ -37,6 +41,16 @@ export function FamilyMemberTreeRoute(): React.ReactElement {
 | 
			
		||||
 | 
			
		||||
  const member = family.members.get(Number(memberId));
 | 
			
		||||
 | 
			
		||||
  const tree = React.useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      !member
 | 
			
		||||
        ? null
 | 
			
		||||
        : currMode === TreeMode.Ascending
 | 
			
		||||
        ? buildAscendingTree(member.id, family.members, family.couples)
 | 
			
		||||
        : buildDescendingTree(member.id, family.members, family.couples),
 | 
			
		||||
    [member, currMode, family.members, family.couples]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (!member) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Alert severity="error">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { useNavigate } from "react-router-dom";
 | 
			
		||||
import { MemberInput } from "../../widgets/forms/MemberInput";
 | 
			
		||||
import { useFamily } from "../../widgets/BaseFamilyRoute";
 | 
			
		||||
import { MemberInput } from "../../widgets/forms/MemberInput";
 | 
			
		||||
 | 
			
		||||
export function FamilyTreeRoute(): React.ReactElement {
 | 
			
		||||
  const n = useNavigate();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								geneit_app/src/utils/family_tree.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								geneit_app/src/utils/family_tree.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
import { Couple, CouplesList } from "../api/CoupleApi";
 | 
			
		||||
import { Member, MembersList } from "../api/MemberApi";
 | 
			
		||||
 | 
			
		||||
export interface CoupleInformation {
 | 
			
		||||
  couple: Couple;
 | 
			
		||||
  member: Member;
 | 
			
		||||
  down: FamilyTreeNode[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FamilyTreeNode {
 | 
			
		||||
  down?: FamilyTreeNode[];
 | 
			
		||||
  member: Member;
 | 
			
		||||
  couples?: CoupleInformation[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function buildAscendingTree(
 | 
			
		||||
  memberId: number,
 | 
			
		||||
  members: MembersList,
 | 
			
		||||
  couples: CouplesList
 | 
			
		||||
): FamilyTreeNode {
 | 
			
		||||
  const member = members.get(memberId)!;
 | 
			
		||||
 | 
			
		||||
  const parents = [];
 | 
			
		||||
  if (member.father)
 | 
			
		||||
    parents.push(buildAscendingTree(member.father, members, couples));
 | 
			
		||||
 | 
			
		||||
  if (member.mother)
 | 
			
		||||
    parents.push(buildAscendingTree(member.mother, members, couples));
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    member: member,
 | 
			
		||||
    down: parents,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function buildDescendingTree(
 | 
			
		||||
  memberId: number,
 | 
			
		||||
  members: MembersList,
 | 
			
		||||
  couples: CouplesList
 | 
			
		||||
): FamilyTreeNode {
 | 
			
		||||
  const member = members.get(memberId)!;
 | 
			
		||||
 | 
			
		||||
  const children = members.children(member.id);
 | 
			
		||||
 | 
			
		||||
  // Process user couples
 | 
			
		||||
  const member_couples: CoupleInformation[] = [];
 | 
			
		||||
  for (const c of couples.getAllOf(member)) {
 | 
			
		||||
    // Currently, couples with missing pair information are not supported
 | 
			
		||||
    const pairId = c.otherPersonID(member.id);
 | 
			
		||||
    if (!pairId) continue;
 | 
			
		||||
    const pair = members.get(pairId);
 | 
			
		||||
 | 
			
		||||
    const c_children: Member[] = [];
 | 
			
		||||
 | 
			
		||||
    // Determine children associated with each couple
 | 
			
		||||
    for (let index = 0; index < children.length; ) {
 | 
			
		||||
      const c = children[index];
 | 
			
		||||
      if (c.mother !== pairId && c.father !== pairId) {
 | 
			
		||||
        index++;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      children.splice(index, 1);
 | 
			
		||||
      c_children.push(c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    member_couples.push({
 | 
			
		||||
      couple: c,
 | 
			
		||||
      member: pair!,
 | 
			
		||||
      down: c_children.map((c) => buildDescendingTree(c.id, members, couples)),
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    member: member,
 | 
			
		||||
    down: children.map((c) => buildDescendingTree(c.id, members, couples)),
 | 
			
		||||
    couples: member_couples,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user