Show couples on members page

This commit is contained in:
Pierre HUBERT 2023-08-16 14:29:22 +02:00
parent ec856b5cb4
commit 23fb77b152
4 changed files with 84 additions and 11 deletions

View File

@ -1,5 +1,5 @@
import { APIClient } from "./ApiClient"; import { APIClient } from "./ApiClient";
import { DateValue } from "./MemberApi"; import { DateValue, Member } from "./MemberApi";
interface CoupleApiInterface { interface CoupleApiInterface {
id: number; id: number;
@ -129,6 +129,10 @@ export class CouplesList {
get(id: number): Couple | undefined { get(id: number): Couple | undefined {
return this.map.get(id); return this.map.get(id);
} }
getAllOf(m: Member): Couple[] {
return this.filter((c) => c.husband === m.id || c.wife === m.id);
}
} }
export class CoupleApi { export class CoupleApi {

View File

@ -3,11 +3,18 @@ import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit"; import EditIcon from "@mui/icons-material/Edit";
import FileDownloadIcon from "@mui/icons-material/FileDownload"; import FileDownloadIcon from "@mui/icons-material/FileDownload";
import SaveIcon from "@mui/icons-material/Save"; 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 * as EmailValidator from "email-validator";
import React from "react"; import React from "react";
import { useNavigate, useParams } from "react-router-dom"; 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 { ServerApi } from "../../api/ServerApi";
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider"; import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider"; import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider";
@ -27,6 +34,8 @@ import { PropEdit } from "../../widgets/forms/PropEdit";
import { PropSelect } from "../../widgets/forms/SelectInput"; import { PropSelect } from "../../widgets/forms/SelectInput";
import { SexSelection } from "../../widgets/forms/SexSelection"; import { SexSelection } from "../../widgets/forms/SexSelection";
import { UploadPhotoButton } from "../../widgets/forms/UploadPhotoButton"; import { UploadPhotoButton } from "../../widgets/forms/UploadPhotoButton";
import { Couple } from "../../api/CoupleApi";
import { CouplePhoto } from "../../widgets/CouplePhoto";
/** /**
* Create a new member route * Create a new member route
@ -129,6 +138,7 @@ export function FamilyMemberRoute(): React.ReactElement {
member={member!} member={member!}
children={family.members.children(member!.id)} children={family.members.children(member!.id)}
siblings={family.members.siblings(member!.id)} siblings={family.members.siblings(member!.id)}
couples={family.couples.getAllOf(member!)}
creating={false} creating={false}
editing={false} editing={false}
onRequestDelete={deleteMember} onRequestDelete={deleteMember}
@ -209,6 +219,7 @@ export function MemberPage(p: {
shouldAllowLeaving?: boolean; shouldAllowLeaving?: boolean;
children?: Member[]; children?: Member[];
siblings?: Member[]; siblings?: Member[];
couples?: Couple[];
onCancel?: () => void; onCancel?: () => void;
onSave?: (m: Member) => void; onSave?: (m: Member) => void;
onRequestEdit?: () => void; onRequestEdit?: () => void;
@ -606,12 +617,20 @@ export function MemberPage(p: {
</Grid> </Grid>
)} )}
{/* Spouse */} {/* Couples */}
<Grid item sm={12} md={6}> {p.couples && (
<PropertiesBox title={member.sex === "F" ? "Époux" : "Épouse"}> <Grid item sm={12} md={6}>
TODO <PropertiesBox title={member.sex === "F" ? "Époux" : "Épouse"}>
</PropertiesBox> {p.couples!.length === 0 ? (
</Grid> <>{member.sex === "F" ? "Aucun époux" : "Aucune épouse"}</>
) : (
p.couples.map((c) => (
<CoupleItem key={c.id} currMemberId={member.id} couple={c} />
))
)}
</PropertiesBox>
</Grid>
)}
{/* Children */} {/* Children */}
{p.children && ( {p.children && (
@ -656,3 +675,47 @@ export function MemberPage(p: {
</div> </div>
); );
} }
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 (
<ListItemButton onClick={() => n(family.family.coupleURL(p.couple))}>
<ListItemAvatar>
{p.couple.hasPhoto ? (
<CouplePhoto couple={p.couple!} />
) : (
<MemberPhoto member={otherSpouse} />
)}
</ListItemAvatar>
<ListItemText
primary={otherSpouse ? otherSpouse.fullName : "___ ___"}
secondary={status.join(" - ")}
></ListItemText>
</ListItemButton>
);
}

View File

@ -31,10 +31,12 @@ import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { AsyncWidget } from "./AsyncWidget"; import { AsyncWidget } from "./AsyncWidget";
import { RouterLink } from "./RouterLink"; import { RouterLink } from "./RouterLink";
import { CoupleApi, CouplesList } from "../api/CoupleApi";
interface FamilyContext { interface FamilyContext {
family: Family; family: Family;
members: MembersList; members: MembersList;
couples: CouplesList;
familyId: number; familyId: number;
reloadFamilyInfo: () => void; reloadFamilyInfo: () => void;
reloadMembersList: () => Promise<void>; reloadMembersList: () => Promise<void>;
@ -51,6 +53,7 @@ export function BaseFamilyRoute(): React.ReactElement {
const [family, setFamily] = React.useState<null | Family>(null); const [family, setFamily] = React.useState<null | Family>(null);
const [members, setMembers] = React.useState<null | MembersList>(null); const [members, setMembers] = React.useState<null | MembersList>(null);
const [couples, setCouples] = React.useState<null | CouplesList>(null);
const loadKey = React.useRef(1); const loadKey = React.useRef(1);
@ -60,12 +63,14 @@ export function BaseFamilyRoute(): React.ReactElement {
const familyID = Number(familyId); const familyID = Number(familyId);
setFamily(await FamilyApi.GetSingle(familyID)); setFamily(await FamilyApi.GetSingle(familyID));
setMembers(await MemberApi.GetEntireList(familyID)); setMembers(await MemberApi.GetEntireList(familyID));
setCouples(await CoupleApi.GetEntireList(familyID));
}; };
const onReload = async () => { const onReload = async () => {
loadKey.current += 1; loadKey.current += 1;
setFamily(null); setFamily(null);
setMembers(null); setMembers(null);
setCouples(null);
return new Promise<void>((res, _rej) => { return new Promise<void>((res, _rej) => {
loadPromise.current = () => res(); loadPromise.current = () => res();
@ -114,6 +119,7 @@ export function BaseFamilyRoute(): React.ReactElement {
value={{ value={{
family: family!, family: family!,
members: members!, members: members!,
couples: couples!,
familyId: family!.family_id, familyId: family!.family_id,
reloadFamilyInfo: onReload, reloadFamilyInfo: onReload,
reloadMembersList: onReload, reloadMembersList: onReload,

View File

@ -2,7 +2,7 @@ import { Avatar } from "@mui/material";
import { Member } from "../api/MemberApi"; import { Member } from "../api/MemberApi";
export function MemberPhoto(p: { export function MemberPhoto(p: {
member: Member; member?: Member;
width?: number; width?: number;
}): React.ReactElement { }): React.ReactElement {
return ( return (
@ -13,7 +13,7 @@ export function MemberPhoto(p: {
: undefined : undefined
} }
variant="rounded" variant="rounded"
src={p.member.thumbnailURL ?? undefined} src={p.member?.thumbnailURL ?? undefined}
/> />
); );
} }