diff --git a/geneit_app/src/api/CoupleApi.ts b/geneit_app/src/api/CoupleApi.ts index 00f7ab7..4199d6e 100644 --- a/geneit_app/src/api/CoupleApi.ts +++ b/geneit_app/src/api/CoupleApi.ts @@ -1,5 +1,5 @@ import { APIClient } from "./ApiClient"; -import { DateValue } from "./MemberApi"; +import { DateValue, Member } from "./MemberApi"; interface CoupleApiInterface { id: number; @@ -129,6 +129,10 @@ export class CouplesList { get(id: number): Couple | undefined { return this.map.get(id); } + + getAllOf(m: Member): Couple[] { + return this.filter((c) => c.husband === m.id || c.wife === m.id); + } } export class CoupleApi { diff --git a/geneit_app/src/routes/family/FamilyMemberRoute.tsx b/geneit_app/src/routes/family/FamilyMemberRoute.tsx index 420375c..e68c22e 100644 --- a/geneit_app/src/routes/family/FamilyMemberRoute.tsx +++ b/geneit_app/src/routes/family/FamilyMemberRoute.tsx @@ -3,11 +3,18 @@ import DeleteIcon from "@mui/icons-material/Delete"; import EditIcon from "@mui/icons-material/Edit"; import FileDownloadIcon from "@mui/icons-material/FileDownload"; import SaveIcon from "@mui/icons-material/Save"; -import { Button, Grid, Stack } from "@mui/material"; +import { + Button, + Grid, + ListItemAvatar, + ListItemButton, + ListItemText, + Stack, +} from "@mui/material"; import * as EmailValidator from "email-validator"; import React from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Member, MemberApi } from "../../api/MemberApi"; +import { Member, MemberApi, fmtDate } from "../../api/MemberApi"; import { ServerApi } from "../../api/ServerApi"; import { useAlert } from "../../hooks/context_providers/AlertDialogProvider"; import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider"; @@ -27,6 +34,8 @@ import { PropEdit } from "../../widgets/forms/PropEdit"; import { PropSelect } from "../../widgets/forms/SelectInput"; import { SexSelection } from "../../widgets/forms/SexSelection"; import { UploadPhotoButton } from "../../widgets/forms/UploadPhotoButton"; +import { Couple } from "../../api/CoupleApi"; +import { CouplePhoto } from "../../widgets/CouplePhoto"; /** * Create a new member route @@ -129,6 +138,7 @@ export function FamilyMemberRoute(): React.ReactElement { member={member!} children={family.members.children(member!.id)} siblings={family.members.siblings(member!.id)} + couples={family.couples.getAllOf(member!)} creating={false} editing={false} onRequestDelete={deleteMember} @@ -209,6 +219,7 @@ export function MemberPage(p: { shouldAllowLeaving?: boolean; children?: Member[]; siblings?: Member[]; + couples?: Couple[]; onCancel?: () => void; onSave?: (m: Member) => void; onRequestEdit?: () => void; @@ -606,12 +617,20 @@ export function MemberPage(p: { )} - {/* Spouse */} - - - TODO - - + {/* Couples */} + {p.couples && ( + + + {p.couples!.length === 0 ? ( + <>{member.sex === "F" ? "Aucun époux" : "Aucune épouse"} + ) : ( + p.couples.map((c) => ( + + )) + )} + + + )} {/* Children */} {p.children && ( @@ -656,3 +675,47 @@ export function MemberPage(p: { ); } + +function CoupleItem(p: { + currMemberId: number; + couple: Couple; +}): React.ReactElement { + const n = useNavigate(); + + const family = useFamily(); + + const statusStr = ServerApi.Config.couples_states.find( + (c) => c.code === p.couple.state + )?.fr; + + const status = []; + if (statusStr) status.push(statusStr); + + if (p.couple.dateOfWedding) + status.push(`Mariage : ${fmtDate(p.couple.dateOfWedding)}`); + + if (p.couple.dateOfDivorce) + status.push(`Divorce : ${fmtDate(p.couple.dateOfDivorce)}`); + + const otherSpouseID = + p.couple.wife === p.currMemberId ? p.couple.husband : p.couple.wife; + const otherSpouse = otherSpouseID + ? family.members.get(otherSpouseID) + : undefined; + + return ( + n(family.family.coupleURL(p.couple))}> + + {p.couple.hasPhoto ? ( + + ) : ( + + )} + + + + ); +} diff --git a/geneit_app/src/widgets/BaseFamilyRoute.tsx b/geneit_app/src/widgets/BaseFamilyRoute.tsx index a59538d..8528afb 100644 --- a/geneit_app/src/widgets/BaseFamilyRoute.tsx +++ b/geneit_app/src/widgets/BaseFamilyRoute.tsx @@ -31,10 +31,12 @@ import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider"; import { useSnackbar } from "../hooks/context_providers/SnackbarProvider"; import { AsyncWidget } from "./AsyncWidget"; import { RouterLink } from "./RouterLink"; +import { CoupleApi, CouplesList } from "../api/CoupleApi"; interface FamilyContext { family: Family; members: MembersList; + couples: CouplesList; familyId: number; reloadFamilyInfo: () => void; reloadMembersList: () => Promise; @@ -51,6 +53,7 @@ export function BaseFamilyRoute(): React.ReactElement { const [family, setFamily] = React.useState(null); const [members, setMembers] = React.useState(null); + const [couples, setCouples] = React.useState(null); const loadKey = React.useRef(1); @@ -60,12 +63,14 @@ export function BaseFamilyRoute(): React.ReactElement { const familyID = Number(familyId); setFamily(await FamilyApi.GetSingle(familyID)); setMembers(await MemberApi.GetEntireList(familyID)); + setCouples(await CoupleApi.GetEntireList(familyID)); }; const onReload = async () => { loadKey.current += 1; setFamily(null); setMembers(null); + setCouples(null); return new Promise((res, _rej) => { loadPromise.current = () => res(); @@ -114,6 +119,7 @@ export function BaseFamilyRoute(): React.ReactElement { value={{ family: family!, members: members!, + couples: couples!, familyId: family!.family_id, reloadFamilyInfo: onReload, reloadMembersList: onReload, diff --git a/geneit_app/src/widgets/MemberPhoto.tsx b/geneit_app/src/widgets/MemberPhoto.tsx index a0de049..5e19f06 100644 --- a/geneit_app/src/widgets/MemberPhoto.tsx +++ b/geneit_app/src/widgets/MemberPhoto.tsx @@ -2,7 +2,7 @@ import { Avatar } from "@mui/material"; import { Member } from "../api/MemberApi"; export function MemberPhoto(p: { - member: Member; + member?: Member; width?: number; }): React.ReactElement { return ( @@ -13,7 +13,7 @@ export function MemberPhoto(p: { : undefined } variant="rounded" - src={p.member.thumbnailURL ?? undefined} + src={p.member?.thumbnailURL ?? undefined} /> ); }