betagouv/service-national-universel

View on GitHub
admin/src/components/selectStatusMission.jsx

Summary

Maintainability
C
1 day
Test Coverage
import React, { useEffect, useState } from "react";
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from "reactstrap";
import styled from "styled-components";
import { toastr } from "react-redux-toastr";
import { useSelector } from "react-redux";

import api from "../services/api";
import { translate, MISSION_STATUS_COLORS, MISSION_STATUS, ROLES, colors } from "../utils";
import MailCorrectionMission from "../scenes/missions/components/MailCorrectionMission";
import MailRefusedMission from "../scenes/missions/components/MailRefusedMission";
import Chevron from "./Chevron";
import ModalConfirm from "./modals/ModalConfirm";
import ModalConfirmWithMessage from "./modals/ModalConfirmWithMessage";

export default function SelectStatusMission({ hit, options = [], callback = () => {} }) {
  const [waitingCorrectionModal, setWaitingCorrectionModal] = useState(false);
  const [refusedModal, setRefusedModal] = useState(false);
  const [mission, setMission] = useState(null);
  const [modal, setModal] = useState({ isOpen: false, onConfirm: null });
  const [modalConfirmWithMessage, setModalConfirmWithMessage] = useState({ isOpen: false, onConfirm: null });
  const user = useSelector((state) => state.Auth.user);

  useEffect(() => {
    (async () => {
      const id = hit && hit._id;
      if (!id) return setMission(null);
      const { data } = await api.get(`/mission/${id}`);
      setMission(data);
    })();
  }, [hit._id]);

  if (!mission) return <i style={{ color: colors.darkPurple }}>Chargement...</i>;

  if (user.role === ROLES.RESPONSIBLE || user.role === ROLES.SUPERVISOR)
    options.push(MISSION_STATUS.WAITING_VALIDATION, MISSION_STATUS.DRAFT, MISSION_STATUS.CANCEL, MISSION_STATUS.ARCHIVED);
  if (user.role === ROLES.ADMIN || user.role === ROLES.REFERENT_DEPARTMENT || user.role === ROLES.REFERENT_REGION) options = Object.keys(MISSION_STATUS);

  const onClickStatus = (status) => {
    if (status === MISSION_STATUS.CANCEL) {
      setModalConfirmWithMessage({
        isOpen: true,
        onConfirm: (statusComment) => onConfirmStatus(status, statusComment),
        title: `Annulation de la mission ${mission.name}`,
        message:
          "Veuillez préciser le motif d'annulation ci-dessous avant de confirmer l'action. Un email sera envoyé à tous les volontaires dont la candidature n'a pas été validée ou refusée pour les prévenir de cette annulation. Leur statut sera passé automatiquement en \"Annulée\". Cette action est irréversible.",
        placeholder: "Veuillez éditer ce message pour préciser le motif d'annulation...",
      });
    } else if (status === MISSION_STATUS.ARCHIVED) {
      setModalConfirmWithMessage({
        isOpen: true,
        onConfirm: (statusComment) => onConfirmStatus(status, statusComment),
        title: `Archivage de la mission ${mission.name}`,
        message:
          "Veuillez préciser le motif d'archivage ci-dessous avant de confirmer l'action. Un email sera envoyé à tous les volontaires dont la candidature n'a pas été validée ou refusée pour les prévenir de cet archivage. Leur statut sera passé automatiquement en \"Annulée\". Cette action est irréversible.",
        placeholder: "Veuillez éditer ce message pour préciser le motif d'archivage...",
      });
    } else {
      setModal({
        isOpen: true,
        onConfirm: () => onConfirmStatus(status),
        title: `Changement de statut de mission`,
        message: `Êtes-vous sûr(e) de vouloir modifier le statut de cette mission de "${translate(mission.status)}" à "${translate(status)}" ?`,
      });
    }
  };

  const onConfirmStatus = (status, statusComment = "") => {
    if (status === MISSION_STATUS.WAITING_CORRECTION && mission.tutorId) return setWaitingCorrectionModal(true);
    if (status === MISSION_STATUS.REFUSED && mission.tutorId) return setRefusedModal(true);
    setStatus(status, statusComment);
  };

  const setStatus = async (status, statusComment = "") => {
    try {
      const { ok, code, data: newMission } = await api.put(`/mission/${mission._id}`, { ...mission, status, statusComment });
      if (!ok) return toastr.error("Une erreur s'est produite :", translate(code));
      setMission(newMission);
      toastr.success("Mis à jour!");
      callback(newMission);
    } catch (e) {
      console.log(e);
      toastr.error("Oups, une erreur est survenue :", translate(e.code));
    }
  };

  return (
    <>
      {waitingCorrectionModal && (
        <MailCorrectionMission
          value={mission}
          onChange={() => setWaitingCorrectionModal(false)}
          onSend={(note) => {
            setStatus(MISSION_STATUS.WAITING_CORRECTION, note);
            setWaitingCorrectionModal(false);
          }}
        />
      )}
      {refusedModal && (
        <MailRefusedMission
          value={mission}
          onChange={() => setRefusedModal(false)}
          onSend={(note) => {
            setStatus(MISSION_STATUS.REFUSED, note);
            setRefusedModal(false);
          }}
        />
      )}
      <ActionBox color={MISSION_STATUS_COLORS[mission.status]}>
        <UncontrolledDropdown setActiveFromChild>
          <DropdownToggle tag="button">
            {translate(mission.status)}
            <Chevron color={MISSION_STATUS_COLORS[mission.status]} />
          </DropdownToggle>
          <DropdownMenu>
            {options
              .filter((e) => e !== mission.status)
              .map((status) => {
                return (
                  <DropdownItem key={status} className="dropdown-item" onClick={() => onClickStatus(status)}>
                    {translate(status)}
                  </DropdownItem>
                );
              })}
          </DropdownMenu>
        </UncontrolledDropdown>
        {/* <div>{JSON.stringify(young)}</div> */}
      </ActionBox>
      <ModalConfirm
        isOpen={modal?.isOpen}
        title={modal?.title}
        message={modal?.message}
        onCancel={() => setModal({ isOpen: false, onConfirm: null })}
        onConfirm={() => {
          modal?.onConfirm();
          setModal({ isOpen: false, onConfirm: null });
        }}
      />
      <ModalConfirmWithMessage
        isOpen={modalConfirmWithMessage.isOpen}
        title={modalConfirmWithMessage.title}
        message={modalConfirmWithMessage.message}
        placeholder={modalConfirmWithMessage.placeholder}
        onChange={() => setModalConfirmWithMessage({ isOpen: false, onConfirm: null })}
        onConfirm={(statusComment) => {
          modalConfirmWithMessage?.onConfirm(statusComment);
          setModalConfirmWithMessage({ isOpen: false, onConfirm: null });
        }}
      />
    </>
  );
}

const ActionBox = styled.div`
  .dropdown-menu {
    min-width: 0;
    a,
    div {
      white-space: nowrap;
      font-size: 14px;
      padding: 5px 15px;
    }
  }
  button {
    ${({ color }) => `
      background-color: ${color}15;
      border: 1px solid ${color};
      color: ${color};
    `}
    display: inline-flex;
    flex: 1;
    justify-content: space-between;
    align-items: center;
    text-align: left;
    border-radius: 0.5rem;
    padding: 0 0 0 12px;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    outline: 0;
    width: 100%;
    max-width: 250px;
    min-width: 250px;
    .edit-icon {
      height: 17px;
      margin-right: 10px;
      path {
        fill: ${({ color }) => `${color}`};
      }
    }
    .down-icon {
      margin-left: auto;
      padding: 7px 15px;
      margin-left: 15px;
      svg {
        height: 10px;
      }
      svg polygon {
        fill: ${({ color }) => `${color}`};
      }
    }
  }
  .dropdown-item {
    background-color: transparent;
    border: none;
    color: #767676;
    white-space: nowrap;
    font-size: 14px;
    padding: 5px 15px;
    font-weight: 400;
    width: 100%;
    :hover {
      background-color: #f3f3f3;
    }
  }
`;