Can download / delete member photo
This commit is contained in:
		@@ -199,6 +199,16 @@ export class MemberApi {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Remove the photo of a member
 | 
			
		||||
   */
 | 
			
		||||
  static async RemoveMemberPhoto(m: Member): Promise<void> {
 | 
			
		||||
    await APIClient.exec({
 | 
			
		||||
      uri: `/family/${m.family_id}/member/${m.id}/photo`,
 | 
			
		||||
      method: "DELETE",
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete a family member
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import EditIcon from "@mui/icons-material/Edit";
 | 
			
		||||
import SaveIcon from "@mui/icons-material/Save";
 | 
			
		||||
import { Button, Grid, Stack } from "@mui/material";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import FileDownloadIcon from "@mui/icons-material/FileDownload";
 | 
			
		||||
import { useNavigate, useParams } from "react-router-dom";
 | 
			
		||||
import { Member, MemberApi } from "../../api/MemberApi";
 | 
			
		||||
import { ServerApi } from "../../api/ServerApi";
 | 
			
		||||
@@ -21,6 +22,7 @@ import { PropEdit } from "../../widgets/forms/PropEdit";
 | 
			
		||||
import { SexSelection } from "../../widgets/forms/SexSelection";
 | 
			
		||||
import { UploadPhotoButton } from "../../widgets/forms/UploadPhotoButton";
 | 
			
		||||
import { MemberPhoto } from "../../widgets/MemberPhoto";
 | 
			
		||||
import { RouterLink } from "../../widgets/RouterLink";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create a new member route
 | 
			
		||||
@@ -238,6 +240,20 @@ export function MemberPage(p: {
 | 
			
		||||
    p.onForceReload?.();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const deletePhoto = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      if (!(await confirm("Voulez-vous supprimer cette photo ?"))) return;
 | 
			
		||||
 | 
			
		||||
      await MemberApi.RemoveMemberPhoto(member);
 | 
			
		||||
 | 
			
		||||
      snackbar("La photo du membre a été supprimée avec succès !");
 | 
			
		||||
      p.onForceReload?.();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error(e);
 | 
			
		||||
      alert("Échec de la suppresion de la photo !");
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div style={{ maxWidth: "2000px", margin: "auto" }}>
 | 
			
		||||
      <ConfirmLeaveWithoutSaveDialog
 | 
			
		||||
@@ -410,11 +426,6 @@ export function MemberPage(p: {
 | 
			
		||||
          </PropertiesBox>
 | 
			
		||||
        </Grid>
 | 
			
		||||
 | 
			
		||||
        {/* Contact */}
 | 
			
		||||
        <Grid item sm={12} md={6}>
 | 
			
		||||
          <PropertiesBox title="Contact">TODO</PropertiesBox>
 | 
			
		||||
        </Grid>
 | 
			
		||||
 | 
			
		||||
        {/* Photo */}
 | 
			
		||||
        <Grid item sm={12} md={6}>
 | 
			
		||||
          <PropertiesBox title="Photo">
 | 
			
		||||
@@ -429,19 +440,40 @@ export function MemberPage(p: {
 | 
			
		||||
              ) : (
 | 
			
		||||
                <>
 | 
			
		||||
                  <UploadPhotoButton
 | 
			
		||||
                    label={
 | 
			
		||||
                      member.hasPhoto
 | 
			
		||||
                        ? "Remplacer la photo"
 | 
			
		||||
                        : "Ajouter une photo"
 | 
			
		||||
                    }
 | 
			
		||||
                    label={member.hasPhoto ? "Remplacer" : "Ajouter"}
 | 
			
		||||
                    onPhotoSelected={uploadNewPhoto}
 | 
			
		||||
                  />
 | 
			
		||||
                  />{" "}
 | 
			
		||||
                  {member.hasPhoto && (
 | 
			
		||||
                    <RouterLink to={member.photoURL} target="_blank">
 | 
			
		||||
                      <Button
 | 
			
		||||
                        variant="outlined"
 | 
			
		||||
                        startIcon={<FileDownloadIcon />}
 | 
			
		||||
                      >
 | 
			
		||||
                        Télécharger
 | 
			
		||||
                      </Button>
 | 
			
		||||
                    </RouterLink>
 | 
			
		||||
                  )}{" "}
 | 
			
		||||
                  {member.hasPhoto && (
 | 
			
		||||
                    <Button
 | 
			
		||||
                      variant="outlined"
 | 
			
		||||
                      startIcon={<DeleteIcon />}
 | 
			
		||||
                      color="error"
 | 
			
		||||
                      onClick={deletePhoto}
 | 
			
		||||
                    >
 | 
			
		||||
                      Supprimer
 | 
			
		||||
                    </Button>
 | 
			
		||||
                  )}
 | 
			
		||||
                </>
 | 
			
		||||
              )}{" "}
 | 
			
		||||
            </div>
 | 
			
		||||
          </PropertiesBox>
 | 
			
		||||
        </Grid>
 | 
			
		||||
 | 
			
		||||
        {/* Contact */}
 | 
			
		||||
        <Grid item sm={12} md={6}>
 | 
			
		||||
          <PropertiesBox title="Contact">TODO</PropertiesBox>
 | 
			
		||||
        </Grid>
 | 
			
		||||
 | 
			
		||||
        {/* Bio */}
 | 
			
		||||
        <Grid item sm={12} md={6}>
 | 
			
		||||
          <PropertiesBox title="Biographie">TODO</PropertiesBox>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,14 @@ import { PropsWithChildren } from "react";
 | 
			
		||||
import { Link } from "react-router-dom";
 | 
			
		||||
 | 
			
		||||
export function RouterLink(
 | 
			
		||||
  p: PropsWithChildren<{ to: string }>
 | 
			
		||||
  p: PropsWithChildren<{ to: string; target?: React.HTMLAttributeAnchorTarget }>
 | 
			
		||||
): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <Link to={p.to} style={{ color: "inherit", textDecoration: "inherit" }}>
 | 
			
		||||
    <Link
 | 
			
		||||
      to={p.to}
 | 
			
		||||
      target={p.target}
 | 
			
		||||
      style={{ color: "inherit", textDecoration: "inherit" }}
 | 
			
		||||
    >
 | 
			
		||||
      {p.children}
 | 
			
		||||
    </Link>
 | 
			
		||||
  );
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { ImageCropperDialog } from "../../dialogs/ImageCropperDialog";
 | 
			
		||||
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
 | 
			
		||||
import { Area } from "react-easy-crop";
 | 
			
		||||
import getCroppedImg from "../../utils/crop_image";
 | 
			
		||||
import UploadIcon from "@mui/icons-material/Upload";
 | 
			
		||||
 | 
			
		||||
export function UploadPhotoButton(p: {
 | 
			
		||||
  label: string;
 | 
			
		||||
@@ -82,7 +83,13 @@ export function UploadPhotoButton(p: {
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      {/* Upload button */}
 | 
			
		||||
      <Button onClick={uploadPhoto}>{p.label}</Button>
 | 
			
		||||
      <Button
 | 
			
		||||
        onClick={uploadPhoto}
 | 
			
		||||
        variant="outlined"
 | 
			
		||||
        startIcon={<UploadIcon />}
 | 
			
		||||
      >
 | 
			
		||||
        {p.label}
 | 
			
		||||
      </Button>
 | 
			
		||||
 | 
			
		||||
      {/* Crop image dialog */}
 | 
			
		||||
      {imageURL && (
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user