Show children on member page
This commit is contained in:
		| @@ -191,6 +191,10 @@ export class MembersList { | ||||
|   get(id: number): Member | undefined { | ||||
|     return this.map.get(id); | ||||
|   } | ||||
|  | ||||
|   children(id: number): Member[] { | ||||
|     return this.list.filter((m) => m.mother === id || m.father === id); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class MemberApi { | ||||
|   | ||||
| @@ -26,6 +26,7 @@ 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 { MemberItem } from "../../widgets/MemberItem"; | ||||
|  | ||||
| /** | ||||
|  * Create a new member route | ||||
| @@ -126,6 +127,7 @@ export function FamilyMemberRoute(): React.ReactElement { | ||||
|       build={() => ( | ||||
|         <MemberPage | ||||
|           member={member!} | ||||
|           children={family.members.children(member!.id)} | ||||
|           creating={false} | ||||
|           editing={false} | ||||
|           onRequestDelete={deleteMember} | ||||
| @@ -144,13 +146,14 @@ export function FamilyMemberRoute(): React.ReactElement { | ||||
|  */ | ||||
| export function FamilyEditMemberRoute(): React.ReactElement { | ||||
|   const n = useNavigate(); | ||||
|   const { memberId } = useParams(); | ||||
|  | ||||
|   const alert = useAlert(); | ||||
|   const snackbar = useSnackbar(); | ||||
|  | ||||
|   const [shouldQuit, setShouldQuit] = React.useState(false); | ||||
|  | ||||
|   const family = useFamily(); | ||||
|   const { memberId } = useParams(); | ||||
|  | ||||
|   const [member, setMember] = React.useState<Member>(); | ||||
|   const load = async () => { | ||||
| @@ -202,6 +205,7 @@ export function MemberPage(p: { | ||||
|   editing: boolean; | ||||
|   creating: boolean; | ||||
|   shouldAllowLeaving?: boolean; | ||||
|   children?: Member[]; | ||||
|   onCancel?: () => void; | ||||
|   onSave?: (m: Member) => void; | ||||
|   onRequestEdit?: () => void; | ||||
| @@ -211,6 +215,8 @@ export function MemberPage(p: { | ||||
|   const confirm = useConfirm(); | ||||
|   const snackbar = useSnackbar(); | ||||
|  | ||||
|   const family = useFamily(); | ||||
|  | ||||
|   const [changed, setChanged] = React.useState(false); | ||||
|   const [member, setMember] = React.useState( | ||||
|     new Member(structuredClone(p.member)) | ||||
| @@ -604,9 +610,24 @@ export function MemberPage(p: { | ||||
|         </Grid> | ||||
|  | ||||
|         {/* Children */} | ||||
|         <Grid item sm={12} md={6}> | ||||
|           <PropertiesBox title="Enfants">TODO</PropertiesBox> | ||||
|         </Grid> | ||||
|         {p.children && ( | ||||
|           <Grid item sm={12} md={6}> | ||||
|             <PropertiesBox title="Enfants"> | ||||
|               {p.children.length === 0 ? ( | ||||
|                 <>Aucun enfant</> | ||||
|               ) : ( | ||||
|                 p.children.map((c) => ( | ||||
|                   <RouterLink | ||||
|                     key={c.id} | ||||
|                     to={family.family.URL(`member/${c.id}`)} | ||||
|                   > | ||||
|                     <MemberItem member={c} /> | ||||
|                   </RouterLink> | ||||
|                 )) | ||||
|               )} | ||||
|             </PropertiesBox> | ||||
|           </Grid> | ||||
|         )} | ||||
|       </Grid> | ||||
|     </div> | ||||
|   ); | ||||
|   | ||||
							
								
								
									
										45
									
								
								geneit_app/src/widgets/MemberItem.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								geneit_app/src/widgets/MemberItem.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| import { mdiCross } from "@mdi/js"; | ||||
| import { | ||||
|   ListItemAvatar, | ||||
|   ListItemButton, | ||||
|   ListItemSecondaryAction, | ||||
|   ListItemText, | ||||
| } from "@mui/material"; | ||||
| import { Member, fmtDate } from "../api/MemberApi"; | ||||
| import { MemberPhoto } from "./MemberPhoto"; | ||||
| import Icon from "@mdi/react"; | ||||
| import FemaleIcon from "@mui/icons-material/Female"; | ||||
| import MaleIcon from "@mui/icons-material/Male"; | ||||
|  | ||||
| export function MemberItem(p: { | ||||
|   member?: Member; | ||||
|   onClick?: () => void; | ||||
|   secondary?: React.ReactElement; | ||||
| }): React.ReactElement { | ||||
|   return ( | ||||
|     <ListItemButton onClick={p.onClick}> | ||||
|       <ListItemAvatar> | ||||
|         <MemberPhoto member={p.member!} /> | ||||
|       </ListItemAvatar> | ||||
|       <ListItemText | ||||
|         primary={ | ||||
|           <> | ||||
|             {p.member?.fullName}{" "} | ||||
|             {p.member?.sex === "F" ? ( | ||||
|               <FemaleIcon fontSize="small" htmlColor="pink" /> | ||||
|             ) : ( | ||||
|               <MaleIcon fontSize="small" htmlColor="lightBlue" /> | ||||
|             )}{" "} | ||||
|             {p.member?.dead && <Icon path={mdiCross} size={"1rem"} />} | ||||
|           </> | ||||
|         } | ||||
|         secondary={`${fmtDate(p.member?.dateOfBirth)} - ${fmtDate( | ||||
|           p.member?.dateOfDeath | ||||
|         )}`} | ||||
|       /> | ||||
|       {p.secondary && ( | ||||
|         <ListItemSecondaryAction>{p.secondary}</ListItemSecondaryAction> | ||||
|       )} | ||||
|     </ListItemButton> | ||||
|   ); | ||||
| } | ||||
| @@ -1,21 +1,10 @@ | ||||
| import { mdiCross } from "@mdi/js"; | ||||
| import Icon from "@mdi/react"; | ||||
| import ClearIcon from "@mui/icons-material/Clear"; | ||||
| import { | ||||
|   Autocomplete, | ||||
|   IconButton, | ||||
|   ListItemAvatar, | ||||
|   ListItemButton, | ||||
|   ListItemSecondaryAction, | ||||
|   ListItemText, | ||||
|   TextField, | ||||
|   Typography, | ||||
| } from "@mui/material"; | ||||
| import { Autocomplete, IconButton, TextField, Typography } from "@mui/material"; | ||||
| import React from "react"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import { Member, fmtDate } from "../../api/MemberApi"; | ||||
| import { Member } from "../../api/MemberApi"; | ||||
| import { useFamily } from "../BaseFamilyRoute"; | ||||
| import { MemberPhoto } from "../MemberPhoto"; | ||||
| import { MemberItem } from "../MemberItem"; | ||||
|  | ||||
| export function MemberInput(p: { | ||||
|   editable: boolean; | ||||
| @@ -92,31 +81,3 @@ export function MemberInput(p: { | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function MemberItem(p: { | ||||
|   member?: Member; | ||||
|   onClick?: () => void; | ||||
|   secondary?: React.ReactElement; | ||||
| }): React.ReactElement { | ||||
|   return ( | ||||
|     <ListItemButton onClick={p.onClick}> | ||||
|       <ListItemAvatar> | ||||
|         <MemberPhoto member={p.member!} /> | ||||
|       </ListItemAvatar> | ||||
|       <ListItemText | ||||
|         primary={ | ||||
|           <> | ||||
|             {p.member?.fullName}{" "} | ||||
|             {p.member?.dead && <Icon path={mdiCross} size={"1rem"} />} | ||||
|           </> | ||||
|         } | ||||
|         secondary={`${fmtDate(p.member?.dateOfBirth)} - ${fmtDate( | ||||
|           p.member?.dateOfDeath | ||||
|         )}`} | ||||
|       /> | ||||
|       {p.secondary && ( | ||||
|         <ListItemSecondaryAction>{p.secondary}</ListItemSecondaryAction> | ||||
|       )} | ||||
|     </ListItemButton> | ||||
|   ); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user