Compare commits
	
		
			8 Commits
		
	
	
		
			c972df0656
			...
			2889569238
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2889569238 | ||
| 
						 | 
					0b02a71a1a | ||
| d9781b6396 | |||
| 0df30c74c9 | |||
| 
						 | 
					59d0f5eae6 | ||
| 
						 | 
					57cc2bc1fa | ||
| 
						 | 
					ce775e03ab | ||
| 3a0426ae6d | 
@@ -5,19 +5,25 @@ import "./modalLayout.scss";
 | 
			
		||||
export const ModalLayout = ({
 | 
			
		||||
  active,
 | 
			
		||||
  setActive,
 | 
			
		||||
  onClose,
 | 
			
		||||
  children,
 | 
			
		||||
  styles,
 | 
			
		||||
  type,
 | 
			
		||||
  ...props
 | 
			
		||||
}) => {
 | 
			
		||||
  const handleClose = (event) => {
 | 
			
		||||
    if (event.target.className === "modal-layout active") {
 | 
			
		||||
      setActive(false);
 | 
			
		||||
      if (onClose) {
 | 
			
		||||
        onClose(); // Вызов колбэк-функции при закрытии модального окна
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className={active ? `modal-layout active` : "modal-layout"}
 | 
			
		||||
      onClick={(event) => {
 | 
			
		||||
        if (event.target.className === "modal-layout active") {
 | 
			
		||||
          setActive(false);
 | 
			
		||||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      onClick={handleClose}
 | 
			
		||||
      {...props}
 | 
			
		||||
    >
 | 
			
		||||
      <div
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        row-gap: 5px;
 | 
			
		||||
        &__input {
 | 
			
		||||
          margin: 0;
 | 
			
		||||
          margin: 10px 0 10px 0;
 | 
			
		||||
          min-width: 240px;
 | 
			
		||||
          height: 42px;
 | 
			
		||||
 | 
			
		||||
@@ -79,6 +79,9 @@
 | 
			
		||||
          max-width: 190px;
 | 
			
		||||
          width: 100%;
 | 
			
		||||
        }
 | 
			
		||||
        .email-error-message {
 | 
			
		||||
          color: red;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 805px) {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import {
 | 
			
		||||
  modalToggle
 | 
			
		||||
} from "@redux/projectsTrackerSlice";
 | 
			
		||||
 | 
			
		||||
import { caseOfNum, urlForLocal } from "@utils/helper";
 | 
			
		||||
import { caseOfNum, removeLast, urlForLocal } from "@utils/helper";
 | 
			
		||||
 | 
			
		||||
import { apiRequest } from "@api/request";
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +67,7 @@ const ListEmployees = ({
 | 
			
		||||
                  }
 | 
			
		||||
                  alt="avatar"
 | 
			
		||||
                />
 | 
			
		||||
                <span>{person.user.fio}</span>
 | 
			
		||||
                <span>{removeLast(person.user.fio)}</span>
 | 
			
		||||
                <img
 | 
			
		||||
                  className="delete"
 | 
			
		||||
                  src={close}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,10 +11,10 @@ import { getProfileInfo } from "@redux/outstaffingSlice";
 | 
			
		||||
import { setProjectBoardFetch } from "@redux/projectsTrackerSlice";
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  backendImg,
 | 
			
		||||
  caseOfNum,
 | 
			
		||||
  getCorrectRequestDate,
 | 
			
		||||
  getToken,
 | 
			
		||||
  removeLast,
 | 
			
		||||
  urlForLocal
 | 
			
		||||
} from "@utils/helper";
 | 
			
		||||
 | 
			
		||||
@@ -99,6 +99,18 @@ export const ModalTiсket = ({
 | 
			
		||||
  const { showNotification } = useNotification();
 | 
			
		||||
  const [commentSendDisable, setCommentSendDisable] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const closeModal = () => {
 | 
			
		||||
    setActive(false);
 | 
			
		||||
    // Восстанавливаем скролл при закрытии модального окна
 | 
			
		||||
    document.body.style.overflow = "auto";
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const [isExpanded, setIsExpanded] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const toggleModalSize = () => {
 | 
			
		||||
    setIsExpanded((prevState) => !prevState);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function deleteTask() {
 | 
			
		||||
    apiRequest("/task/update-task", {
 | 
			
		||||
      method: "PUT",
 | 
			
		||||
@@ -107,7 +119,7 @@ export const ModalTiсket = ({
 | 
			
		||||
        status: 0
 | 
			
		||||
      }
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      setActive(false);
 | 
			
		||||
      closeModal();
 | 
			
		||||
      dispatch(setProjectBoardFetch(projectId));
 | 
			
		||||
      showNotification({
 | 
			
		||||
        show: true,
 | 
			
		||||
@@ -594,20 +606,20 @@ export const ModalTiсket = ({
 | 
			
		||||
    <div
 | 
			
		||||
      className={active ? "modal-ticket active" : "modal-ticket"}
 | 
			
		||||
      onClick={(e) => {
 | 
			
		||||
        if (e.target.className.includes("modal-ticket")) setActive(false);
 | 
			
		||||
        if (e.target.className.includes("modal-ticket")) closeModal();
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div className="modal-ticket__content">
 | 
			
		||||
      <div className={`modal-ticket__content ${isExpanded ? "expanded" : ""}`}>
 | 
			
		||||
        <div className="content">
 | 
			
		||||
          <h3 className="title-project">
 | 
			
		||||
            <img src={category} className="title-project__category"></img>
 | 
			
		||||
            {projectName}
 | 
			
		||||
            <Link
 | 
			
		||||
              to={`/tracker/task/${task.id}`}
 | 
			
		||||
            <img
 | 
			
		||||
              src={fullScreen}
 | 
			
		||||
              alt="Full screen"
 | 
			
		||||
              onClick={toggleModalSize}
 | 
			
		||||
              className="title-project__full"
 | 
			
		||||
            >
 | 
			
		||||
              <img src={fullScreen}></img>
 | 
			
		||||
            </Link>
 | 
			
		||||
            />
 | 
			
		||||
          </h3>
 | 
			
		||||
          <div className="content__task">
 | 
			
		||||
            {editOpen ? (
 | 
			
		||||
@@ -757,14 +769,14 @@ export const ModalTiсket = ({
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="workers">
 | 
			
		||||
          <div className="workers_box task__info">
 | 
			
		||||
            <span className="exit" onClick={() => setActive(false)}></span>
 | 
			
		||||
            <span className="exit" onClick={() => closeModal()}></span>
 | 
			
		||||
            <h5>Создатель: </h5>
 | 
			
		||||
            <p className="workers__creator">{task.user?.fio}</p>
 | 
			
		||||
            <p className="workers__creator">{removeLast(task.user?.fio)}</p>
 | 
			
		||||
            {executor ? (
 | 
			
		||||
              <>
 | 
			
		||||
                <h5>Исполнитель: </h5>
 | 
			
		||||
                <div className="executor">
 | 
			
		||||
                  <p>{executor.fio}</p>
 | 
			
		||||
                  <p>{removeLast(executor.fio)}</p>
 | 
			
		||||
                  <img
 | 
			
		||||
                    src={
 | 
			
		||||
                      executor?.avatar
 | 
			
		||||
@@ -803,7 +815,7 @@ export const ModalTiсket = ({
 | 
			
		||||
                          key={person.user_id}
 | 
			
		||||
                          onClick={() => taskExecutor(person)}
 | 
			
		||||
                        >
 | 
			
		||||
                          <span>{person.user.fio}</span>
 | 
			
		||||
                          <span>{removeLast(person.user.fio)}</span>
 | 
			
		||||
                          <img
 | 
			
		||||
                            src={
 | 
			
		||||
                              person.user?.avatar
 | 
			
		||||
@@ -826,7 +838,7 @@ export const ModalTiсket = ({
 | 
			
		||||
                  {members.map((member) => {
 | 
			
		||||
                    return (
 | 
			
		||||
                      <div className="worker" key={member.user_id}>
 | 
			
		||||
                        <p>{member.fio}</p>
 | 
			
		||||
                        <p>{removeLast(member.fio)}</p>
 | 
			
		||||
                        <img
 | 
			
		||||
                          src={
 | 
			
		||||
                            member?.avatar
 | 
			
		||||
@@ -869,7 +881,7 @@ export const ModalTiсket = ({
 | 
			
		||||
                          key={person.user_id}
 | 
			
		||||
                          onClick={() => addMember(person)}
 | 
			
		||||
                        >
 | 
			
		||||
                          <span>{person.user.fio}</span>
 | 
			
		||||
                          <span>{removeLast(person.user.fio)}</span>
 | 
			
		||||
                          <img
 | 
			
		||||
                            src={
 | 
			
		||||
                              person.user?.avatar
 | 
			
		||||
@@ -895,7 +907,7 @@ export const ModalTiсket = ({
 | 
			
		||||
                className="dead-line__container"
 | 
			
		||||
                onClick={() => setDatePickerOpen(!datePickerOpen)}
 | 
			
		||||
              >
 | 
			
		||||
                <img src={calendarIcon} alt="calendar" />
 | 
			
		||||
                <p>⌛</p>
 | 
			
		||||
                <span>
 | 
			
		||||
                  {deadLine ? getCorrectDate(deadLine) : "Срок исполнения"}
 | 
			
		||||
                </span>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,13 +15,20 @@
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.modal-ticket__content.expanded {
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  max-height: none;
 | 
			
		||||
  max-width: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.modal-ticket__content {
 | 
			
		||||
  background: #ffffff;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  max-height: 700px;
 | 
			
		||||
  // overflow-y: auto;
 | 
			
		||||
  max-width: 915px;
 | 
			
		||||
 | 
			
		||||
  @media (max-width: 990px) {
 | 
			
		||||
    width: 96%;
 | 
			
		||||
@@ -52,7 +59,7 @@
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    width: 630px;
 | 
			
		||||
    width: 68%;
 | 
			
		||||
    margin: 26px 0 0 21px;
 | 
			
		||||
 | 
			
		||||
    .title-project {
 | 
			
		||||
@@ -160,7 +167,6 @@
 | 
			
		||||
 | 
			
		||||
      .comments__list {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        overflow-y: auto;
 | 
			
		||||
        height: 190px;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
 | 
			
		||||
@@ -364,7 +370,6 @@
 | 
			
		||||
      column-gap: 25px;
 | 
			
		||||
      row-gap: 20px;
 | 
			
		||||
      margin-top: 33px;
 | 
			
		||||
      overflow-y: auto;
 | 
			
		||||
 | 
			
		||||
      .task-file {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
@@ -607,6 +612,7 @@
 | 
			
		||||
  .workers {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    border-left: 1px solid #f1f1f1;
 | 
			
		||||
    width: 32%;
 | 
			
		||||
 | 
			
		||||
    .exit {
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
 
 | 
			
		||||
@@ -950,7 +950,7 @@ export const TicketFullScreen = () => {
 | 
			
		||||
                      className="dead-line__container"
 | 
			
		||||
                      onClick={() => setDatePickerOpen(!datePickerOpen)}
 | 
			
		||||
                    >
 | 
			
		||||
                      <img src={calendarIcon} alt="calendar" />
 | 
			
		||||
                      <p>⌛</p>
 | 
			
		||||
                      <span>
 | 
			
		||||
                        {deadLine
 | 
			
		||||
                          ? getCorrectDate(deadLine)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ import {
 | 
			
		||||
} from "@redux/projectsTrackerSlice";
 | 
			
		||||
 | 
			
		||||
import { getCorrectDate } from "@utils/calendarHelper";
 | 
			
		||||
import { getCorrectRequestDate, urlForLocal } from "@utils/helper";
 | 
			
		||||
import { getCorrectRequestDate, removeLast, urlForLocal } from "@utils/helper";
 | 
			
		||||
 | 
			
		||||
import { apiRequest } from "@api/request";
 | 
			
		||||
 | 
			
		||||
@@ -72,6 +72,7 @@ export const TrackerModal = ({
 | 
			
		||||
  const [selectWorkersOpen, setSelectWorkersOpen] = useState(false);
 | 
			
		||||
  const [selectedWorker, setSelectedWorker] = useState(null);
 | 
			
		||||
  const [emailWorker, setEmailWorker] = useState("");
 | 
			
		||||
  const [emailError, setEmailError] = useState("");
 | 
			
		||||
  const [selectColumnPriority, setSelectColumnPriority] = useState(
 | 
			
		||||
    "Выберите приоритет колонки"
 | 
			
		||||
  );
 | 
			
		||||
@@ -114,6 +115,19 @@ export const TrackerModal = ({
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const existingColumn = projectBoard.columns.find(
 | 
			
		||||
      (column) => column.title === valueColumn
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (existingColumn) {
 | 
			
		||||
      showNotification({
 | 
			
		||||
        show: true,
 | 
			
		||||
        text: "Колонка с таким названием уже существует",
 | 
			
		||||
        type: "error"
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    apiRequest("/project-column/create-column", {
 | 
			
		||||
      method: "POST",
 | 
			
		||||
      data: {
 | 
			
		||||
@@ -325,19 +339,6 @@ export const TrackerModal = ({
 | 
			
		||||
      setActive(false);
 | 
			
		||||
      setSelectedWorker("");
 | 
			
		||||
      setSelectWorkersOpen(false);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function inviteUserByEmail() {
 | 
			
		||||
    apiRequest("/project/add-user-by-email", {
 | 
			
		||||
      method: "POST",
 | 
			
		||||
      data: {
 | 
			
		||||
        email: emailWorker,
 | 
			
		||||
        project_id: projectBoard.id
 | 
			
		||||
      }
 | 
			
		||||
    }).then((el) => {
 | 
			
		||||
      setActive(false);
 | 
			
		||||
      setEmailWorker("");
 | 
			
		||||
      showNotification({
 | 
			
		||||
        show: true,
 | 
			
		||||
        text: "Приглашение отправлено",
 | 
			
		||||
@@ -346,6 +347,35 @@ export const TrackerModal = ({
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const validateEmail = (email) => {
 | 
			
		||||
    // Простая валидация адреса электронной почты
 | 
			
		||||
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
 | 
			
		||||
    return emailPattern.test(email);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const inviteUserByEmail = () => {
 | 
			
		||||
    if (validateEmail(emailWorker)) {
 | 
			
		||||
      setEmailError("");
 | 
			
		||||
      apiRequest("/project/add-user-by-email", {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        data: {
 | 
			
		||||
          email: emailWorker,
 | 
			
		||||
          project_id: projectBoard.id
 | 
			
		||||
        }
 | 
			
		||||
      }).then((el) => {
 | 
			
		||||
        setActive(false);
 | 
			
		||||
        setEmailWorker("");
 | 
			
		||||
        showNotification({
 | 
			
		||||
          show: true,
 | 
			
		||||
          text: "Приглашение отправлено",
 | 
			
		||||
          type: "success"
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      setEmailError("Некорректный e-mail адрес");
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    modalType === "add-worker"
 | 
			
		||||
      ? apiRequest("/project/my-employee").then((el) => {
 | 
			
		||||
@@ -426,8 +456,18 @@ export const TrackerModal = ({
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleModalClose = () => {
 | 
			
		||||
    setEmailError("");
 | 
			
		||||
    setEmailWorker("");
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ModalLayout active={active} setActive={setActive} type={modalType}>
 | 
			
		||||
    <ModalLayout
 | 
			
		||||
      active={active}
 | 
			
		||||
      setActive={setActive}
 | 
			
		||||
      onClose={handleModalClose}
 | 
			
		||||
      type={modalType}
 | 
			
		||||
    >
 | 
			
		||||
      {modalType === "add-worker" && (
 | 
			
		||||
        <>
 | 
			
		||||
          <div className="select__person">
 | 
			
		||||
@@ -448,7 +488,7 @@ export const TrackerModal = ({
 | 
			
		||||
                  >
 | 
			
		||||
                    <p>
 | 
			
		||||
                      {selectedWorker
 | 
			
		||||
                        ? selectedWorker.employee.fio
 | 
			
		||||
                        ? removeLast(selectedWorker.employee.fio)
 | 
			
		||||
                        : "Выберите пользователя"}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <img className="arrow" src={arrowDown} alt="arrow" />
 | 
			
		||||
@@ -467,7 +507,7 @@ export const TrackerModal = ({
 | 
			
		||||
                                  setSelectedWorker(worker);
 | 
			
		||||
                                }}
 | 
			
		||||
                              >
 | 
			
		||||
                                <span>{worker.employee.fio}</span>
 | 
			
		||||
                                <span>{removeLast(worker.employee.fio)}</span>
 | 
			
		||||
                                <img
 | 
			
		||||
                                  src={urlForLocal(worker.employee.avatar)}
 | 
			
		||||
                                  alt="avatar"
 | 
			
		||||
@@ -498,6 +538,7 @@ export const TrackerModal = ({
 | 
			
		||||
                      value={emailWorker}
 | 
			
		||||
                      onChange={(e) => setEmailWorker(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
                    <div className="email-error-message">{emailError}</div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <BaseButton
 | 
			
		||||
                    styles={"button-add add-person-btn"}
 | 
			
		||||
@@ -521,7 +562,6 @@ export const TrackerModal = ({
 | 
			
		||||
            </div>
 | 
			
		||||
            <div className="create-task-body">
 | 
			
		||||
              <div className="create-task-body__left">
 | 
			
		||||
                <h4>Введите название и описание задачи</h4>
 | 
			
		||||
                <div className="input-container">
 | 
			
		||||
                  <input
 | 
			
		||||
                    maxLength="100"
 | 
			
		||||
@@ -699,7 +739,7 @@ export const TrackerModal = ({
 | 
			
		||||
                                }
 | 
			
		||||
                                alt="avatar"
 | 
			
		||||
                              />
 | 
			
		||||
                              <span>{person.user.fio}</span>
 | 
			
		||||
                              <span>{removeLast(person.user.fio)}</span>
 | 
			
		||||
                            </div>
 | 
			
		||||
                          );
 | 
			
		||||
                        })
 | 
			
		||||
@@ -710,7 +750,7 @@ export const TrackerModal = ({
 | 
			
		||||
                  )}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className="create-task-body__right__dead-line">
 | 
			
		||||
                  <img src={calendarImg} alt="calendar" />
 | 
			
		||||
                  <p>⌛</p>
 | 
			
		||||
                  <p onClick={() => setDatePickerOpen(!datePickerOpen)}>
 | 
			
		||||
                    {deadLineDate
 | 
			
		||||
                      ? getCorrectDate(deadLineDate)
 | 
			
		||||
@@ -734,7 +774,7 @@ export const TrackerModal = ({
 | 
			
		||||
              <Loader style={"green"} />
 | 
			
		||||
            ) : (
 | 
			
		||||
              <BaseButton styles={"button-add"} onClick={createTicket}>
 | 
			
		||||
                Создать
 | 
			
		||||
                Создать задачу
 | 
			
		||||
              </BaseButton>
 | 
			
		||||
            )}
 | 
			
		||||
          </div>
 | 
			
		||||
@@ -864,7 +904,14 @@ export const TrackerModal = ({
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      <span className="exit" onClick={() => setActive(false)}></span>
 | 
			
		||||
      <span
 | 
			
		||||
        className="exit"
 | 
			
		||||
        onClick={() => {
 | 
			
		||||
          setActive(false);
 | 
			
		||||
          setEmailError("");
 | 
			
		||||
          setEmailWorker("");
 | 
			
		||||
        }}
 | 
			
		||||
      ></span>
 | 
			
		||||
    </ModalLayout>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -227,6 +227,7 @@
 | 
			
		||||
    min-width: 240px;
 | 
			
		||||
    height: 42px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    margin: 10px 0 10px 0;
 | 
			
		||||
 | 
			
		||||
    p {
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
@@ -262,7 +263,7 @@
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      padding: 9.5px 12px;
 | 
			
		||||
      top: 48px;
 | 
			
		||||
      top: 45px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      background: white;
 | 
			
		||||
      border-radius: 5px;
 | 
			
		||||
@@ -337,7 +338,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .create-task-body {
 | 
			
		||||
    padding: 15px 20px;
 | 
			
		||||
    padding: 15px 30px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    column-gap: 20px;
 | 
			
		||||
 | 
			
		||||
@@ -373,8 +374,8 @@
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .ck-editor__editable.ck-rounded-corners {
 | 
			
		||||
        min-height: 150px;
 | 
			
		||||
        max-height: 150px;
 | 
			
		||||
        min-height: 180px;
 | 
			
		||||
        max-height: 180px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -383,6 +384,7 @@
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
      align-items: start;
 | 
			
		||||
      justify-content: end;
 | 
			
		||||
      row-gap: 10px;
 | 
			
		||||
 | 
			
		||||
      &__owner {
 | 
			
		||||
        display: flex;
 | 
			
		||||
@@ -714,6 +716,11 @@
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .button-add {
 | 
			
		||||
    margin: 0 30px;
 | 
			
		||||
    align-self: flex-end;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.name-project {
 | 
			
		||||
 
 | 
			
		||||
@@ -97,7 +97,7 @@ export const Navigation = () => {
 | 
			
		||||
 | 
			
		||||
        <div className="profile-header__personal-info">
 | 
			
		||||
          <h3 className="profile-header__personal-info-name">
 | 
			
		||||
            {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username}
 | 
			
		||||
            {profileInfo?.fio || profileInfo?.username}
 | 
			
		||||
          </h3>
 | 
			
		||||
          <NavLink end to={"/profile"}>
 | 
			
		||||
            <img
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ export const ProfileCalendar = () => {
 | 
			
		||||
              alt="avatar"
 | 
			
		||||
            />
 | 
			
		||||
            <p className="summary__name">
 | 
			
		||||
              {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username},{" "}
 | 
			
		||||
              {profileInfo?.fio || profileInfo?.username},{" "}
 | 
			
		||||
              {profileInfo.specification} разработчик
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +110,10 @@ export const ProfileHeader = () => {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const closeMenu = () => {
 | 
			
		||||
    setActive(false);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <header className="profile-header">
 | 
			
		||||
      <div className="auth-title">
 | 
			
		||||
@@ -146,7 +150,7 @@ export const ProfileHeader = () => {
 | 
			
		||||
        <nav className="auth-body__navigation">
 | 
			
		||||
          <div className="profile-header__personal-info">
 | 
			
		||||
            <h3 className="profile-header__personal-info-name">
 | 
			
		||||
              {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username}
 | 
			
		||||
              {profileInfo?.fio || profileInfo?.username}
 | 
			
		||||
            </h3>
 | 
			
		||||
            <NavLink end to={"/profile"}>
 | 
			
		||||
              <img
 | 
			
		||||
@@ -179,6 +183,7 @@ export const ProfileHeader = () => {
 | 
			
		||||
          </button>
 | 
			
		||||
        </nav>
 | 
			
		||||
      </div>
 | 
			
		||||
      {active && <div className="backdrop" onClick={closeMenu}></div>}
 | 
			
		||||
    </header>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    z-index: 9;
 | 
			
		||||
    max-width: 1160px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
@@ -36,6 +35,7 @@
 | 
			
		||||
 | 
			
		||||
        @media (max-width: 414px) {
 | 
			
		||||
          display: block;
 | 
			
		||||
          z-index: 9;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__line {
 | 
			
		||||
@@ -64,9 +64,19 @@
 | 
			
		||||
    background: white;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .backdrop {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
    z-index: 7;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .auth-body {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    z-index: 99;
 | 
			
		||||
    z-index: 8;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
@@ -99,7 +109,7 @@
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
 | 
			
		||||
      a {
 | 
			
		||||
        padding: 10px 0 0 0;
 | 
			
		||||
        padding: 15px 0 0 10px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      a,
 | 
			
		||||
@@ -134,7 +144,7 @@
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    overflow: visible;
 | 
			
		||||
    width: calc(100vw / 3);
 | 
			
		||||
    width: calc(100vw / 2.5);
 | 
			
		||||
    transition: width 0.3s;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
@@ -188,6 +198,7 @@
 | 
			
		||||
  &__logout-burger {
 | 
			
		||||
    background: none;
 | 
			
		||||
    border: none;
 | 
			
		||||
    padding: 15px 0 0 0;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    line-height: 32px;
 | 
			
		||||
 
 | 
			
		||||
@@ -103,12 +103,12 @@ export const Profile = () => {
 | 
			
		||||
          {user === "developer" ? (
 | 
			
		||||
            <span>
 | 
			
		||||
              <p>Добрый день, </p>
 | 
			
		||||
              {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username}
 | 
			
		||||
              {profileInfo?.fio || profileInfo?.username}
 | 
			
		||||
            </span>
 | 
			
		||||
          ) : (
 | 
			
		||||
            <span>
 | 
			
		||||
              <p>Добрый день, </p>
 | 
			
		||||
              {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username}
 | 
			
		||||
              {profileInfo?.fio || profileInfo?.username}
 | 
			
		||||
            </span>
 | 
			
		||||
          )}
 | 
			
		||||
        </h2>
 | 
			
		||||
@@ -124,13 +124,11 @@ export const Profile = () => {
 | 
			
		||||
            <p className="summary__name">
 | 
			
		||||
              {user === "developer" ? (
 | 
			
		||||
                <span>
 | 
			
		||||
                  {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username},{" "}
 | 
			
		||||
                  {profileInfo?.fio || profileInfo?.username},{" "}
 | 
			
		||||
                  {profileInfo?.specification} разработчик
 | 
			
		||||
                </span>
 | 
			
		||||
              ) : (
 | 
			
		||||
                <span>
 | 
			
		||||
                  {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username}
 | 
			
		||||
                </span>
 | 
			
		||||
                <span>{profileInfo?.fio || profileInfo?.username}</span>
 | 
			
		||||
              )}
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@ import {
 | 
			
		||||
  setToggleTab
 | 
			
		||||
} from "@redux/projectsTrackerSlice";
 | 
			
		||||
 | 
			
		||||
import { urlForLocal } from "@utils/helper";
 | 
			
		||||
import { caseOfNum } from "@utils/helper";
 | 
			
		||||
import { removeLast, urlForLocal } from "@utils/helper";
 | 
			
		||||
 | 
			
		||||
import { apiRequest } from "@api/request";
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +43,6 @@ import TrackerSelectColumn from "@components/TrackerSelectColumn/TrackerSelectCo
 | 
			
		||||
 | 
			
		||||
import arrow from "assets/icons/arrows/arrowCalendar.png";
 | 
			
		||||
import arrowDown from "assets/icons/arrows/selectArrow.png";
 | 
			
		||||
import calendarIcon from "assets/icons/calendar.svg";
 | 
			
		||||
import category from "assets/icons/category.svg";
 | 
			
		||||
import close from "assets/icons/close.png";
 | 
			
		||||
import commentsBoard from "assets/icons/commentsBoard.svg";
 | 
			
		||||
@@ -64,7 +62,6 @@ export const ProjectTracker = () => {
 | 
			
		||||
  const dispatch = useDispatch();
 | 
			
		||||
  const projectId = useParams();
 | 
			
		||||
 | 
			
		||||
  const currentDate = new Date().getFullYear();
 | 
			
		||||
  const [openColumnSelect, setOpenColumnSelect] = useState({});
 | 
			
		||||
  const [selectedTab, setSelectedTab] = useState(0);
 | 
			
		||||
  const [priorityTask, setPriorityTask] = useState(0);
 | 
			
		||||
@@ -224,11 +221,9 @@ export const ProjectTracker = () => {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function openTicket(e, task) {
 | 
			
		||||
    if (window.innerWidth < 985) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    setSelectedTicket(task);
 | 
			
		||||
    setModalActiveTicket(true);
 | 
			
		||||
    document.body.style.overflow = "hidden";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function deleteColumn(column) {
 | 
			
		||||
@@ -612,7 +607,7 @@ export const ProjectTracker = () => {
 | 
			
		||||
                                key={user.user_id}
 | 
			
		||||
                                onClick={() => executorFilter(user)}
 | 
			
		||||
                              >
 | 
			
		||||
                                <p>{user.user?.fio}</p>
 | 
			
		||||
                                <p>{removeLast(user.user?.fio)}</p>
 | 
			
		||||
                                <img
 | 
			
		||||
                                  src={
 | 
			
		||||
                                    user.user?.avatar
 | 
			
		||||
@@ -910,10 +905,7 @@ export const ProjectTracker = () => {
 | 
			
		||||
                                    }
 | 
			
		||||
                                  }}
 | 
			
		||||
                                >
 | 
			
		||||
                                  <p
 | 
			
		||||
                                    className="task__board__item__title"
 | 
			
		||||
                                    style={{ color: titleColor }}
 | 
			
		||||
                                  >
 | 
			
		||||
                                  <p className="task__board__item__title">
 | 
			
		||||
                                    {task.title}
 | 
			
		||||
                                  </p>
 | 
			
		||||
                                </div>
 | 
			
		||||
@@ -955,7 +947,7 @@ export const ProjectTracker = () => {
 | 
			
		||||
                                  {task.dead_line && (
 | 
			
		||||
                                    <div className="tasks__board__item__dead-line">
 | 
			
		||||
                                      <p>⌛</p>
 | 
			
		||||
                                      <span>
 | 
			
		||||
                                      <span style={{ color: titleColor }}>
 | 
			
		||||
                                        {getCorrectDate(task.dead_line)}
 | 
			
		||||
                                      </span>
 | 
			
		||||
                                    </div>
 | 
			
		||||
@@ -973,7 +965,7 @@ export const ProjectTracker = () => {
 | 
			
		||||
                                      alt="avatar"
 | 
			
		||||
                                    />
 | 
			
		||||
                                    <span>
 | 
			
		||||
                                      {task.executor?.fio ||
 | 
			
		||||
                                      {removeLast(task.executor?.fio) ||
 | 
			
		||||
                                        "Исполнитель не назначен"}
 | 
			
		||||
                                    </span>
 | 
			
		||||
                                  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -40,8 +40,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @media (max-width: 483px) {
 | 
			
		||||
          max-width: 160px;
 | 
			
		||||
          left: -175px;
 | 
			
		||||
          display: none;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -62,6 +61,20 @@
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: -100px;
 | 
			
		||||
      right: 58px;
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 1100px) {
 | 
			
		||||
        max-width: 100px;
 | 
			
		||||
        top: -50px;
 | 
			
		||||
        right: 25px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 800px) {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @media (max-width: 1100px) {
 | 
			
		||||
      padding: 20px 25px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -73,12 +86,23 @@
 | 
			
		||||
    &__head {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      margin-bottom: 33px;
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 650px) {
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        row-gap: 10px;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__suptitle {
 | 
			
		||||
      color: #6f6f6f;
 | 
			
		||||
      font-size: 14px;
 | 
			
		||||
      margin-right: 70px;
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 650px) {
 | 
			
		||||
        margin-right: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__steps {
 | 
			
		||||
@@ -102,12 +126,17 @@
 | 
			
		||||
      font-size: 20px;
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: #000000;
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 650px) {
 | 
			
		||||
        text-align: center;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__answers {
 | 
			
		||||
      margin-top: 45px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      column-gap: 20px;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
      gap: 20px;
 | 
			
		||||
 | 
			
		||||
      button {
 | 
			
		||||
        border-radius: 12px;
 | 
			
		||||
@@ -120,8 +149,16 @@
 | 
			
		||||
      .active {
 | 
			
		||||
        background: #1458dd;
 | 
			
		||||
        color: whitesmoke;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        border: none;
 | 
			
		||||
        border: 1px solid #1458dd;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 1100px) {
 | 
			
		||||
        gap: 10px;
 | 
			
		||||
        margin-top: 20px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @media (max-width: 450px) {
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -152,6 +189,7 @@
 | 
			
		||||
        row-gap: 19px;
 | 
			
		||||
        column-gap: 21px;
 | 
			
		||||
        margin-bottom: 30px;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &__item {
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@ export const Summary = () => {
 | 
			
		||||
                alt="avatar"
 | 
			
		||||
              />
 | 
			
		||||
              <p className="summary__name">
 | 
			
		||||
                {profileInfo?.fio ? profileInfo?.fio : profileInfo?.username},{" "}
 | 
			
		||||
                {profileInfo?.fio || profileInfo?.username},{" "}
 | 
			
		||||
                {profileInfo.specification} разработчик
 | 
			
		||||
              </p>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -91,3 +91,11 @@ export function copyProjectLink(projectId) {
 | 
			
		||||
    `https://itguild.info/tracker/project/${projectId}`
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function removeLast(string = " ") {
 | 
			
		||||
  let arr = string.trim().split(" ");
 | 
			
		||||
  if (arr.length > 2) {
 | 
			
		||||
    return arr.slice(0, -1).join(" ");
 | 
			
		||||
  }
 | 
			
		||||
  return string;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user