Can create a member
This commit is contained in:
		@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import { APIClient } from "./ApiClient";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Sex = "M" | "F";
 | 
					export type Sex = "M" | "F";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MemberApi {
 | 
					export interface MemberApi {
 | 
				
			||||||
@@ -85,4 +87,30 @@ export class Member implements MemberApi {
 | 
				
			|||||||
    this.death_day = m.death_day;
 | 
					    this.death_day = m.death_day;
 | 
				
			||||||
    this.note = m.note;
 | 
					    this.note = m.note;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Create an empty member object
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static New(family_id: number): Member {
 | 
				
			||||||
 | 
					    return new Member({
 | 
				
			||||||
 | 
					      id: 0,
 | 
				
			||||||
 | 
					      dead: false,
 | 
				
			||||||
 | 
					      family_id: family_id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class MemberApi {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Create a new member
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async Create(m: Member): Promise<Member> {
 | 
				
			||||||
 | 
					    const res = await APIClient.exec({
 | 
				
			||||||
 | 
					      uri: `/family/${m.family_id}/member/create`,
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      jsonData: m,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new Member(res.data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,49 @@
 | 
				
			|||||||
 | 
					import ClearIcon from "@mui/icons-material/Clear";
 | 
				
			||||||
 | 
					import SaveIcon from "@mui/icons-material/Save";
 | 
				
			||||||
 | 
					import { Button, Grid, Stack } from "@mui/material";
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import { Member } from "../../api/MemberApi";
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
import { useFamily } from "../../widgets/BaseFamilyRoute";
 | 
					import { Member, MemberApi } from "../../api/MemberApi";
 | 
				
			||||||
import { Grid, Typography } from "@mui/material";
 | 
					 | 
				
			||||||
import { PropertiesBox } from "../../widgets/PropertiesBox";
 | 
					 | 
				
			||||||
import { PropEdit } from "../../widgets/PropEdit";
 | 
					 | 
				
			||||||
import { ServerApi } from "../../api/ServerApi";
 | 
					import { ServerApi } from "../../api/ServerApi";
 | 
				
			||||||
 | 
					import { useAlert } from "../../context_providers/AlertDialogProvider";
 | 
				
			||||||
 | 
					import { useConfirm } from "../../context_providers/ConfirmDialogProvider";
 | 
				
			||||||
 | 
					import { useFamily } from "../../widgets/BaseFamilyRoute";
 | 
				
			||||||
 | 
					import { FamilyPageTitle } from "../../widgets/FamilyPageTitle";
 | 
				
			||||||
 | 
					import { PropEdit } from "../../widgets/PropEdit";
 | 
				
			||||||
 | 
					import { PropertiesBox } from "../../widgets/PropertiesBox";
 | 
				
			||||||
import { SexSelection } from "../../widgets/SexSelection";
 | 
					import { SexSelection } from "../../widgets/SexSelection";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Create a new member route
 | 
					 * Create a new member route
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function FamilyCreateMemberRoute(): React.ReactElement {
 | 
					export function FamilyCreateMemberRoute(): React.ReactElement {
 | 
				
			||||||
 | 
					  const alert = useAlert();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const n = useNavigate();
 | 
				
			||||||
  const family = useFamily();
 | 
					  const family = useFamily();
 | 
				
			||||||
  const member = new Member({
 | 
					
 | 
				
			||||||
    id: 0,
 | 
					  const create = async (m: Member) => {
 | 
				
			||||||
    dead: false,
 | 
					    try {
 | 
				
			||||||
    family_id: family.family.family_id,
 | 
					      const r = await MemberApi.Create(m);
 | 
				
			||||||
  });
 | 
					
 | 
				
			||||||
  return <MemberPage member={member} creating={true} forceEdit={true} />;
 | 
					      // TODO : trigger update
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      n(family.family.URL(`member/${r.id}`));
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      console.error(e);
 | 
				
			||||||
 | 
					      alert("Echec de la création de la personne !");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <MemberPage
 | 
				
			||||||
 | 
					      member={Member.New(family.family.family_id)}
 | 
				
			||||||
 | 
					      creating={true}
 | 
				
			||||||
 | 
					      editing={true}
 | 
				
			||||||
 | 
					      onCancel={() => n(family.family.URL("members"))}
 | 
				
			||||||
 | 
					      onSave={create}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -29,21 +55,79 @@ export function FamilyMemberRoute(): React.ReactElement {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export function MemberPage(p: {
 | 
					export function MemberPage(p: {
 | 
				
			||||||
  member: Member;
 | 
					  member: Member;
 | 
				
			||||||
  forceEdit: boolean;
 | 
					  editing: boolean;
 | 
				
			||||||
  creating: boolean;
 | 
					  creating: boolean;
 | 
				
			||||||
 | 
					  onCancel: () => void;
 | 
				
			||||||
 | 
					  onSave: (m: Member) => void;
 | 
				
			||||||
 | 
					  onRequestEdit?: () => void;
 | 
				
			||||||
}): React.ReactElement {
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  const confirm = useConfirm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO : add confirmation when leaving page https://dev.to/bangash1996/detecting-user-leaving-page-with-react-router-dom-v602-33ni
 | 
					  // TODO : add confirmation when leaving page https://dev.to/bangash1996/detecting-user-leaving-page-with-react-router-dom-v602-33ni
 | 
				
			||||||
  const [editing, setEditing] = React.useState(p.forceEdit);
 | 
					  const [changed, setChanged] = React.useState(false);
 | 
				
			||||||
  const [member, setMember] = React.useState(structuredClone(p.member));
 | 
					  const [member, setMember] = React.useState(structuredClone(p.member));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const updatedMember = () => {
 | 
					  const updatedMember = () => {
 | 
				
			||||||
    // TODO : add confirmation
 | 
					    // TODO : add confirmation
 | 
				
			||||||
 | 
					    setChanged(true);
 | 
				
			||||||
    setMember(structuredClone(member));
 | 
					    setMember(structuredClone(member));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const save = () => {
 | 
				
			||||||
 | 
					    p.onSave(member);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const cancel = async () => {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      !(await confirm(
 | 
				
			||||||
 | 
					        "Voulez-vous vraiment retirer les modifications apportées ? Celles-ci seront perdues !"
 | 
				
			||||||
 | 
					      ))
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p.onCancel();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div style={{ maxWidth: "2000px", margin: "auto" }}>
 | 
					    <div style={{ maxWidth: "2000px", margin: "auto" }}>
 | 
				
			||||||
      <Typography variant="h3">Fiche de membre</Typography>
 | 
					      <div
 | 
				
			||||||
 | 
					        style={{
 | 
				
			||||||
 | 
					          display: "flex",
 | 
				
			||||||
 | 
					          justifyContent: "space-between",
 | 
				
			||||||
 | 
					          alignItems: "center",
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FamilyPageTitle
 | 
				
			||||||
 | 
					          title={
 | 
				
			||||||
 | 
					            (p.creating ? "Création" : "Édition") + " d'une fiche de membre"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <Stack direction="row" spacing={1}>
 | 
				
			||||||
 | 
					          {/* Save button */}
 | 
				
			||||||
 | 
					          {p.editing && (
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					              variant="contained"
 | 
				
			||||||
 | 
					              startIcon={<SaveIcon />}
 | 
				
			||||||
 | 
					              onClick={save}
 | 
				
			||||||
 | 
					              size="large"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Enregistrer
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          {/* Cancel button */}
 | 
				
			||||||
 | 
					          {p.editing && (
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					              variant="outlined"
 | 
				
			||||||
 | 
					              startIcon={<ClearIcon />}
 | 
				
			||||||
 | 
					              onClick={cancel}
 | 
				
			||||||
 | 
					              size="small"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Annuler les modifications
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Stack>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      <Grid container spacing={2}>
 | 
					      <Grid container spacing={2}>
 | 
				
			||||||
        <Grid item sm={12} md={6}>
 | 
					        <Grid item sm={12} md={6}>
 | 
				
			||||||
          <PropertiesBox title="Informations générales">
 | 
					          <PropertiesBox title="Informations générales">
 | 
				
			||||||
@@ -59,7 +143,7 @@ export function MemberPage(p: {
 | 
				
			|||||||
            {/* First name */}
 | 
					            {/* First name */}
 | 
				
			||||||
            <PropEdit
 | 
					            <PropEdit
 | 
				
			||||||
              label="Prénom"
 | 
					              label="Prénom"
 | 
				
			||||||
              editable={editing}
 | 
					              editable={p.editing}
 | 
				
			||||||
              value={member.first_name}
 | 
					              value={member.first_name}
 | 
				
			||||||
              onValueChange={(v) => {
 | 
					              onValueChange={(v) => {
 | 
				
			||||||
                member.first_name = v;
 | 
					                member.first_name = v;
 | 
				
			||||||
@@ -71,7 +155,7 @@ export function MemberPage(p: {
 | 
				
			|||||||
            {/* Last name */}
 | 
					            {/* Last name */}
 | 
				
			||||||
            <PropEdit
 | 
					            <PropEdit
 | 
				
			||||||
              label="Nom"
 | 
					              label="Nom"
 | 
				
			||||||
              editable={editing}
 | 
					              editable={p.editing}
 | 
				
			||||||
              value={member.last_name}
 | 
					              value={member.last_name}
 | 
				
			||||||
              onValueChange={(v) => {
 | 
					              onValueChange={(v) => {
 | 
				
			||||||
                member.last_name = v;
 | 
					                member.last_name = v;
 | 
				
			||||||
@@ -81,7 +165,7 @@ export function MemberPage(p: {
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
            <PropEdit
 | 
					            <PropEdit
 | 
				
			||||||
              label="Nom de naissance"
 | 
					              label="Nom de naissance"
 | 
				
			||||||
              editable={editing}
 | 
					              editable={p.editing}
 | 
				
			||||||
              value={member.birth_last_name}
 | 
					              value={member.birth_last_name}
 | 
				
			||||||
              onValueChange={(v) => {
 | 
					              onValueChange={(v) => {
 | 
				
			||||||
                member.birth_last_name = v;
 | 
					                member.birth_last_name = v;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user