Compare commits
10 Commits
page_under
...
4084c52a9b
Author | SHA1 | Date | |
---|---|---|---|
4084c52a9b | |||
b6a4ff6652 | |||
15f8b51327 | |||
1d9a47def4 | |||
9909101660 | |||
ca0a509077 | |||
7e64150378 | |||
911b827e41 | |||
104f538e3a | |||
e27da9fca9 |
BIN
src/assets/images/landing/reportingSystem.webp
Normal file
BIN
src/assets/images/landing/reportingSystem.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
src/assets/images/landing/searchIT.webp
Normal file
BIN
src/assets/images/landing/searchIT.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/images/landing/systemControlGit.webp
Normal file
BIN
src/assets/images/landing/systemControlGit.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
src/assets/images/landing/taskManagement.webp
Normal file
BIN
src/assets/images/landing/taskManagement.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
src/assets/images/landingTracker/target.webp
Normal file
BIN
src/assets/images/landingTracker/target.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -24,19 +24,35 @@ export const Footer = () => {
|
|||||||
<div className="footer__bottom">
|
<div className="footer__bottom">
|
||||||
<div className="footer__social">
|
<div className="footer__social">
|
||||||
<div className="footer__social__icons">
|
<div className="footer__social__icons">
|
||||||
<a href="https://www.vk.com/">
|
<a
|
||||||
|
href="https://www.vk.com/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
<img src={vk} alt="vk" width={24} />
|
<img src={vk} alt="vk" width={24} />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.telegram.org/">
|
<a
|
||||||
|
href="https://www.telegram.org/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
<img src={tg} alt="tg" width={24} />
|
<img src={tg} alt="tg" width={24} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<a href="mailto:office@itguild.info">office@itguild.info</a>
|
<a
|
||||||
|
href="mailto:office@itguild.info"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
office@itguild.info
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="footer__info">
|
<div className="footer__info">
|
||||||
<div className="footer__mail">
|
<div className="footer__mail">
|
||||||
{/* <img src={email} alt="email" /> */}
|
{/* <img src={email} alt="email" /> */}
|
||||||
<a href="#">Присоединиться к команде</a>
|
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||||
|
Присоединиться к команде
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
© {new Date().getFullYear()} - Outstaffing. Все права защищены
|
© {new Date().getFullYear()} - Outstaffing. Все права защищены
|
||||||
|
@ -122,15 +122,6 @@ export const ModalTiсket = ({
|
|||||||
setShowModalToReport(!showModalToReport);
|
setShowModalToReport(!showModalToReport);
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeModal = () => {
|
|
||||||
setActive(false);
|
|
||||||
const currentUrl = window.location.pathname;
|
|
||||||
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
|
||||||
window.history.replaceState({}, "", newUrl);
|
|
||||||
document.body.style.overflow = "auto";
|
|
||||||
console.log(task);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
const toggleModalSize = () => {
|
const toggleModalSize = () => {
|
||||||
@ -310,6 +301,17 @@ export const ModalTiсket = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
if (timerStart) {
|
||||||
|
stopTaskTimer();
|
||||||
|
}
|
||||||
|
setActive(false);
|
||||||
|
const currentUrl = window.location.pathname;
|
||||||
|
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
||||||
|
window.history.replaceState({}, "", newUrl);
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
};
|
||||||
|
|
||||||
function taskExecutor(person) {
|
function taskExecutor(person) {
|
||||||
apiRequest("/task/update-task", {
|
apiRequest("/task/update-task", {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
@ -380,7 +382,22 @@ export const ModalTiсket = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (active) {
|
||||||
|
setStartDate(task.dead_line ? new Date(task.dead_line) : new Date());
|
||||||
|
setTaskPriority(task.execution_priority);
|
||||||
|
setMembers(task.taskUsers);
|
||||||
|
setTaskTags(task.mark);
|
||||||
|
setExecutorId(task.executor_id);
|
||||||
|
setDeadLine(task.dead_line);
|
||||||
|
setExecutor(task.executor);
|
||||||
|
setInputsValue({
|
||||||
|
title: task.title,
|
||||||
|
description: task.description,
|
||||||
|
comment: ""
|
||||||
|
});
|
||||||
|
|
||||||
initListeners();
|
initListeners();
|
||||||
|
|
||||||
apiRequest(
|
apiRequest(
|
||||||
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
|
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
|
||||||
).then((res) => {
|
).then((res) => {
|
||||||
@ -396,8 +413,11 @@ export const ModalTiсket = ({
|
|||||||
}, []);
|
}, []);
|
||||||
setComments(comments);
|
setComments(comments);
|
||||||
});
|
});
|
||||||
apiRequest(`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
|
||||||
(res) => {
|
apiRequest(
|
||||||
|
`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`
|
||||||
|
).then((res) => {
|
||||||
|
if (Array.isArray(res)) {
|
||||||
let timerSeconds = 0;
|
let timerSeconds = 0;
|
||||||
res.length &&
|
res.length &&
|
||||||
res.forEach((time) => {
|
res.forEach((time) => {
|
||||||
@ -410,30 +430,38 @@ export const ModalTiсket = ({
|
|||||||
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
|
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
|
||||||
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
|
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
|
||||||
updateTimerSec = timerSeconds % 60;
|
updateTimerSec = timerSeconds % 60;
|
||||||
|
|
||||||
if (!time.stopped_at) {
|
if (!time.stopped_at) {
|
||||||
setTimerStart(true);
|
setTimerStart(true);
|
||||||
startTimer();
|
startTimer();
|
||||||
setTimerInfo(time);
|
setTimerInfo(time);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setCurrentTimerCount({
|
||||||
|
hours: 0,
|
||||||
|
minute: 0,
|
||||||
|
seconds: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
if (Array.isArray(res)) {
|
if (Array.isArray(res)) {
|
||||||
setTaskFiles(res);
|
setTaskFiles(res);
|
||||||
|
} else {
|
||||||
|
setTaskFiles([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
localStorage.getItem("role_status") !== "18" &&
|
localStorage.getItem("role_status") !== "18" &&
|
||||||
Boolean(
|
Array.isArray(correctProjectUsers) &&
|
||||||
!correctProjectUsers.find(
|
!correctProjectUsers.find(
|
||||||
(item) => item.user_id === profileInfo.id_user
|
(item) => item.user_id === profileInfo.id_user
|
||||||
)
|
)
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
setCorrectProjectUsers((prevState) => [
|
setCorrectProjectUsers((prevState) => [
|
||||||
...prevState,
|
...prevState,
|
||||||
@ -446,16 +474,19 @@ export const ModalTiсket = ({
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}, []);
|
}
|
||||||
|
}, [active]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let tagIds = taskTags.map((tag) => tag.id);
|
if (Array.isArray(taskTags)) {
|
||||||
|
const tagIds = taskTags.map((tag) => tag.id);
|
||||||
setCorrectProjectTags(
|
setCorrectProjectTags(
|
||||||
projectMarks.reduce((acc, cur) => {
|
projectMarks.reduce((acc, cur) => {
|
||||||
if (!tagIds.includes(cur.id)) acc.push(cur);
|
if (!tagIds.includes(cur.id)) acc.push(cur);
|
||||||
return acc;
|
return acc;
|
||||||
}, [])
|
}, [])
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}, [taskTags]);
|
}, [taskTags]);
|
||||||
|
|
||||||
async function handleUpload(event) {
|
async function handleUpload(event) {
|
||||||
@ -534,13 +565,15 @@ export const ModalTiсket = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let ids = members.map((user) => user.user_id);
|
if (Array.isArray(members)) {
|
||||||
|
const ids = members.map((user) => user.user_id);
|
||||||
setUsers(
|
setUsers(
|
||||||
projectUsers.reduce((acc, cur) => {
|
projectUsers.reduce((acc, cur) => {
|
||||||
if (!ids.includes(cur.user_id)) acc.push(cur);
|
if (!ids.includes(cur.user_id)) acc.push(cur);
|
||||||
return acc;
|
return acc;
|
||||||
}, [])
|
}, [])
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}, [members]);
|
}, [members]);
|
||||||
|
|
||||||
function copyTicketLink() {
|
function copyTicketLink() {
|
||||||
@ -684,6 +717,7 @@ export const ModalTiсket = ({
|
|||||||
editor={ClassicEditor}
|
editor={ClassicEditor}
|
||||||
data={inputsValue.description}
|
data={inputsValue.description}
|
||||||
config={{
|
config={{
|
||||||
|
toolbar: ["link"],
|
||||||
removePlugins: [
|
removePlugins: [
|
||||||
"CKFinderUploadAdapter",
|
"CKFinderUploadAdapter",
|
||||||
"CKFinder",
|
"CKFinder",
|
||||||
@ -695,7 +729,10 @@ export const ModalTiсket = ({
|
|||||||
"ImageUpload",
|
"ImageUpload",
|
||||||
"MediaEmbed",
|
"MediaEmbed",
|
||||||
"BlockQuote"
|
"BlockQuote"
|
||||||
]
|
],
|
||||||
|
link: {
|
||||||
|
addTargetToExternalLinks: true
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onChange={(event, editor) => {
|
onChange={(event, editor) => {
|
||||||
const data = editor.getData();
|
const data = editor.getData();
|
||||||
@ -713,7 +750,7 @@ export const ModalTiсket = ({
|
|||||||
)}
|
)}
|
||||||
{/*<img src={taskImg} className="image-task"></img>*/}
|
{/*<img src={taskImg} className="image-task"></img>*/}
|
||||||
</div>
|
</div>
|
||||||
{Boolean(taskFiles.length) && (
|
{Boolean(taskFiles?.length) && (
|
||||||
<div className="task__files">
|
<div className="task__files">
|
||||||
{taskFiles.map((file) => {
|
{taskFiles.map((file) => {
|
||||||
return (
|
return (
|
||||||
@ -873,7 +910,7 @@ export const ModalTiсket = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{Boolean(members.length) && (
|
{Boolean(members?.length) && (
|
||||||
<div className="members">
|
<div className="members">
|
||||||
<h5>Участники:</h5>
|
<h5>Участники:</h5>
|
||||||
<div className="members__list">
|
<div className="members__list">
|
||||||
@ -1005,7 +1042,8 @@ export const ModalTiсket = ({
|
|||||||
<div className="workers_box-tag">
|
<div className="workers_box-tag">
|
||||||
<div className="tags">
|
<div className="tags">
|
||||||
<div className="tags__selected">
|
<div className="tags__selected">
|
||||||
{taskTags.map((tag) => {
|
{Array.isArray(taskTags) &&
|
||||||
|
taskTags.map((tag) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="tags__selected__item"
|
className="tags__selected__item"
|
||||||
|
@ -625,7 +625,10 @@ export const TrackerModal = ({
|
|||||||
"numberedList"
|
"numberedList"
|
||||||
],
|
],
|
||||||
removePlugins: ["BlockQuote"],
|
removePlugins: ["BlockQuote"],
|
||||||
placeholder: "Описание задачи"
|
placeholder: "Описание задачи",
|
||||||
|
link: {
|
||||||
|
addTargetToExternalLinks: true
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onChange={(event, editor) => {
|
onChange={(event, editor) => {
|
||||||
const data = editor.getData();
|
const data = editor.getData();
|
||||||
|
@ -62,10 +62,14 @@ export const SideBar = () => {
|
|||||||
<Link to={"/forms"}>Формы</Link>
|
<Link to={"/forms"}>Формы</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#">Школа</a>
|
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||||
|
Школа
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#">Контакты</a>
|
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||||
|
Контакты
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to={"/blog"}>Блог</Link>
|
<Link to={"/blog"}>Блог</Link>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { forwardRef, useEffect, useState } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
import { movePositionProjectTask } from "@redux/projectsTrackerSlice";
|
import { movePositionProjectTask } from "@redux/projectsTrackerSlice";
|
||||||
@ -14,7 +14,9 @@ import avatarMok from "assets/images/avatarMok.webp";
|
|||||||
|
|
||||||
import "./trackerCardTask.scss";
|
import "./trackerCardTask.scss";
|
||||||
|
|
||||||
const TrackerCardTask = ({
|
const TrackerCardTask = forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
task,
|
task,
|
||||||
projectBoard,
|
projectBoard,
|
||||||
titleColor,
|
titleColor,
|
||||||
@ -22,7 +24,9 @@ const TrackerCardTask = ({
|
|||||||
openTicket,
|
openTicket,
|
||||||
startWrapperIndexTest,
|
startWrapperIndexTest,
|
||||||
setWrapperHover
|
setWrapperHover
|
||||||
}) => {
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [taskHover, setTaskHover] = useState({});
|
const [taskHover, setTaskHover] = useState({});
|
||||||
|
|
||||||
@ -94,6 +98,7 @@ const TrackerCardTask = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={ref}
|
||||||
key={task.id}
|
key={task.id}
|
||||||
className={`tasks__board__item ${
|
className={`tasks__board__item ${
|
||||||
taskHover[task.id] ? "task__hover" : ""
|
taskHover[task.id] ? "task__hover" : ""
|
||||||
@ -104,7 +109,7 @@ const TrackerCardTask = ({
|
|||||||
onDragLeave={(e) => dragLeaveTaskHandler(e)}
|
onDragLeave={(e) => dragLeaveTaskHandler(e)}
|
||||||
onDragEnd={() => dragEndTaskHandler()}
|
onDragEnd={() => dragEndTaskHandler()}
|
||||||
onDrop={(e) => dragDropTaskHandler(e, task, column)}
|
onDrop={(e) => dragDropTaskHandler(e, task, column)}
|
||||||
onClick={(e) => openTicket(e, task)}
|
onClick={() => openTicket(task)}
|
||||||
>
|
>
|
||||||
<div className="tasks__board__item__title">
|
<div className="tasks__board__item__title">
|
||||||
<p className="task__board__item__title">{task.title}</p>
|
<p className="task__board__item__title">{task.title}</p>
|
||||||
@ -181,6 +186,9 @@ const TrackerCardTask = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
TrackerCardTask.displayName = "TrackerCardTask";
|
||||||
|
|
||||||
export default TrackerCardTask;
|
export default TrackerCardTask;
|
||||||
|
@ -121,6 +121,7 @@ export const TrackerTaskComment = ({
|
|||||||
editor={ClassicEditor}
|
editor={ClassicEditor}
|
||||||
data={commentsEditText}
|
data={commentsEditText}
|
||||||
config={{
|
config={{
|
||||||
|
toolbar: ["link"],
|
||||||
removePlugins: [
|
removePlugins: [
|
||||||
"CKFinderUploadAdapter",
|
"CKFinderUploadAdapter",
|
||||||
"CKFinder",
|
"CKFinder",
|
||||||
@ -132,7 +133,10 @@ export const TrackerTaskComment = ({
|
|||||||
"ImageUpload",
|
"ImageUpload",
|
||||||
"MediaEmbed",
|
"MediaEmbed",
|
||||||
"BlockQuote"
|
"BlockQuote"
|
||||||
]
|
],
|
||||||
|
link: {
|
||||||
|
addTargetToExternalLinks: true
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onChange={(event, editor) => {
|
onChange={(event, editor) => {
|
||||||
const data = editor.getData();
|
const data = editor.getData();
|
||||||
|
@ -90,7 +90,11 @@ export const FormPage = () => {
|
|||||||
Заявка на собеседование через телеграм
|
Заявка на собеседование через телеграм
|
||||||
</div>
|
</div>
|
||||||
<div className="form-page__telegram-icon">
|
<div className="form-page__telegram-icon">
|
||||||
<a href="https://t.me/st0kir" target="_blank" rel="noreferrer">
|
<a
|
||||||
|
href="https://t.me/st0kir"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
<SVG src={telegramIcon} />
|
<SVG src={telegramIcon} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,6 +13,10 @@ import clue from "assets/icons/landingClue.svg";
|
|||||||
import tracker from "assets/icons/landingTracker.svg";
|
import tracker from "assets/icons/landingTracker.svg";
|
||||||
import codeBg from "assets/images/landing/backgroundCode.webp";
|
import codeBg from "assets/images/landing/backgroundCode.webp";
|
||||||
import cat from "assets/images/landing/landingCat.webp";
|
import cat from "assets/images/landing/landingCat.webp";
|
||||||
|
import reportingSystem from "assets/images/landing/reportingSystem.webp";
|
||||||
|
import searchIT from "assets/images/landing/searchIT.webp";
|
||||||
|
import systemControlGit from "assets/images/landing/systemControlGit.webp";
|
||||||
|
import taskManagement from "assets/images/landing/taskManagement.webp";
|
||||||
|
|
||||||
import "./landing.scss";
|
import "./landing.scss";
|
||||||
|
|
||||||
@ -29,22 +33,22 @@ export const Landing = () => {
|
|||||||
{
|
{
|
||||||
name: "<span>Найти</span> работу <br/> в IT",
|
name: "<span>Найти</span> работу <br/> в IT",
|
||||||
path: "/stack",
|
path: "/stack",
|
||||||
img: cat
|
img: searchIT
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "<span>Система</span> контроля версий GIT",
|
name: "<span>Система</span> контроля версий GIT",
|
||||||
path: "/stack",
|
path: "/stack",
|
||||||
img: cat
|
img: systemControlGit
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "<span>Управление</span> задачами",
|
name: "<span>Управление</span> задачами",
|
||||||
path: "/landing-tracker",
|
path: "/landing-tracker",
|
||||||
img: cat
|
img: taskManagement
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "<span>Система</span> для отчётности",
|
name: "<span>Система</span> для отчётности",
|
||||||
path: "/stack",
|
path: "/stack",
|
||||||
img: cat
|
img: reportingSystem
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Все наши предложения",
|
name: "Все наши предложения",
|
||||||
|
@ -12,6 +12,7 @@ import ellipseGreen from "assets/images/landingTracker/ellipseGreen.svg";
|
|||||||
import cat from "assets/images/landingTracker/landingCat.webp";
|
import cat from "assets/images/landingTracker/landingCat.webp";
|
||||||
import flag from "assets/images/landingTracker/projectsFlag.webp";
|
import flag from "assets/images/landingTracker/projectsFlag.webp";
|
||||||
import questionMark from "assets/images/landingTracker/questionMark.svg";
|
import questionMark from "assets/images/landingTracker/questionMark.svg";
|
||||||
|
import target from "assets/images/landingTracker/target.webp";
|
||||||
import trackerCup from "assets/images/landingTracker/trackerCup.webp";
|
import trackerCup from "assets/images/landingTracker/trackerCup.webp";
|
||||||
import trackerPreview from "assets/images/landingTracker/trackerPreview.webp";
|
import trackerPreview from "assets/images/landingTracker/trackerPreview.webp";
|
||||||
import trackerSign from "assets/images/landingTracker/trackerSign.webp";
|
import trackerSign from "assets/images/landingTracker/trackerSign.webp";
|
||||||
@ -173,9 +174,9 @@ export const LandingTracker = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="steps__portfolio">
|
<div className="goals__target">
|
||||||
<img src={portfolio} alt="portfolio" />
|
<img src={target} alt="target" />
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -446,6 +446,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__target {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { Link, useParams } from "react-router-dom";
|
import { Link, useLocation, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
activeLoader,
|
activeLoader,
|
||||||
@ -51,6 +51,9 @@ import avatarMok from "assets/images/avatarMok.webp";
|
|||||||
export const ProjectTracker = () => {
|
export const ProjectTracker = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const projectId = useParams();
|
const projectId = useParams();
|
||||||
|
const taskParams = useParams();
|
||||||
|
const taskRefs = useRef([]);
|
||||||
|
const hasRunEffect = useRef(false);
|
||||||
|
|
||||||
const [openColumnSelect, setOpenColumnSelect] = useState({});
|
const [openColumnSelect, setOpenColumnSelect] = useState({});
|
||||||
const [selectedTab, setSelectedTab] = useState(0);
|
const [selectedTab, setSelectedTab] = useState(0);
|
||||||
@ -78,6 +81,19 @@ export const ProjectTracker = () => {
|
|||||||
initListeners();
|
initListeners();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (projectBoard.columns && taskParams.taskId && !hasRunEffect.current) {
|
||||||
|
for (const column of projectBoard.columns) {
|
||||||
|
const task = column.tasks.find((task) => task.id == taskParams.taskId);
|
||||||
|
if (task) {
|
||||||
|
openTicket(task);
|
||||||
|
hasRunEffect.current = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [projectBoard]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let columnsTasksEmpty = true;
|
let columnsTasksEmpty = true;
|
||||||
if (Object.keys(projectBoard).length) {
|
if (Object.keys(projectBoard).length) {
|
||||||
@ -145,21 +161,32 @@ export const ProjectTracker = () => {
|
|||||||
setPriorityTask(length);
|
setPriorityTask(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openTicket(e, task) {
|
const updateUrlWithTaskId = (taskId) => {
|
||||||
|
const currentUrl = window.location.pathname;
|
||||||
|
const taskUrlSegment = `/task/`;
|
||||||
|
|
||||||
|
if (currentUrl.includes(taskUrlSegment)) {
|
||||||
|
// Если URL содержит '/task/', заменяем старый ID на новый
|
||||||
|
const baseUrl = currentUrl.substring(
|
||||||
|
0,
|
||||||
|
currentUrl.indexOf(taskUrlSegment) + taskUrlSegment.length
|
||||||
|
);
|
||||||
|
const newUrl = `${baseUrl}${taskId}`;
|
||||||
|
window.history.pushState({}, "", newUrl);
|
||||||
|
} else {
|
||||||
|
// Если URL не содержит '/task/', добавляем '/task/${taskId}'
|
||||||
|
const newUrl = `${currentUrl}${taskUrlSegment}${taskId}`;
|
||||||
|
window.history.pushState({}, "", newUrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function openTicket(task) {
|
||||||
setSelectedTicket(task);
|
setSelectedTicket(task);
|
||||||
setModalActiveTicket(true);
|
setModalActiveTicket(true);
|
||||||
const currentUrl = window.location.pathname;
|
updateUrlWithTaskId(task.id);
|
||||||
const newUrl = `${currentUrl}/task/${task.id}`;
|
|
||||||
window.history.pushState({}, "", newUrl);
|
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const currentUrl = window.location.pathname;
|
|
||||||
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
|
||||||
window.history.replaceState({}, "", newUrl);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
function deleteColumn(column) {
|
function deleteColumn(column) {
|
||||||
const priorityColumns = [];
|
const priorityColumns = [];
|
||||||
apiRequest("/project-column/update-column", {
|
apiRequest("/project-column/update-column", {
|
||||||
@ -421,8 +448,6 @@ export const ProjectTracker = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{Boolean(modalActiveTicket) && (
|
|
||||||
<ModalTicket
|
<ModalTicket
|
||||||
active={modalActiveTicket}
|
active={modalActiveTicket}
|
||||||
setActive={setModalActiveTicket}
|
setActive={setModalActiveTicket}
|
||||||
@ -433,7 +458,6 @@ export const ProjectTracker = () => {
|
|||||||
projectOwnerId={projectBoard.owner_id}
|
projectOwnerId={projectBoard.owner_id}
|
||||||
projectMarks={projectBoard.mark}
|
projectMarks={projectBoard.mark}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="tasks__container">
|
<div className="tasks__container">
|
||||||
{Boolean(projectBoard?.columns) &&
|
{Boolean(projectBoard?.columns) &&
|
||||||
@ -535,6 +559,9 @@ export const ProjectTracker = () => {
|
|||||||
startWrapperIndexTest={startWrapperIndexTest}
|
startWrapperIndexTest={startWrapperIndexTest}
|
||||||
task={task}
|
task={task}
|
||||||
titleColor={titleColor}
|
titleColor={titleColor}
|
||||||
|
ref={(el) => {
|
||||||
|
taskRefs.current[task.id] = el;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -648,9 +648,15 @@ export const Stack = () => {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<p>
|
<p>
|
||||||
Соглашаюсь с <a href="">Пользовательским соглашением</a> и
|
Соглашаюсь с{" "}
|
||||||
|
<a href="" target="_blank" rel="noopener noreferrer">
|
||||||
|
Пользовательским соглашением
|
||||||
|
</a>{" "}
|
||||||
|
и
|
||||||
<br />
|
<br />
|
||||||
<a href="">Политикой обработки данных</a>
|
<a href="" target="_blank" rel="noopener noreferrer">
|
||||||
|
Политикой обработки данных
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -58,6 +58,25 @@ export const Summary = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const addSkill = (skill) => {
|
||||||
|
const isSkillFound = selectedSkills.some(
|
||||||
|
(item) => item.skill_id == skill.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isSkillFound) {
|
||||||
|
setSelectedSkills((prevValue) => [
|
||||||
|
...prevValue,
|
||||||
|
{ skill: skill, skill_id: skill.id }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteSkill = (skill) => {
|
||||||
|
setSelectedSkills((prevValue) =>
|
||||||
|
prevValue.filter((item) => item.skill_id !== skill.skill_id)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function setSkills() {
|
function setSkills() {
|
||||||
apiRequest("/resume/edit-skills", {
|
apiRequest("/resume/edit-skills", {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
@ -157,13 +176,7 @@ export const Summary = () => {
|
|||||||
<img
|
<img
|
||||||
src={deleteIcon}
|
src={deleteIcon}
|
||||||
alt="deleteIcon"
|
alt="deleteIcon"
|
||||||
onClick={() =>
|
onClick={() => deleteSkill(skill)}
|
||||||
setSelectedSkills((prevValue) =>
|
|
||||||
prevValue.filter(
|
|
||||||
(item) => item.skill_id !== skill.skill_id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
@ -184,12 +197,7 @@ export const Summary = () => {
|
|||||||
{skillsList.map((skill) => {
|
{skillsList.map((skill) => {
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
onClick={() =>
|
onClick={() => addSkill(skill)}
|
||||||
setSelectedSkills((prevValue) => [
|
|
||||||
...prevValue,
|
|
||||||
{ skill: skill, skill_id: skill.id }
|
|
||||||
])
|
|
||||||
}
|
|
||||||
key={skill.id}
|
key={skill.id}
|
||||||
className="select-skills__item"
|
className="select-skills__item"
|
||||||
>
|
>
|
||||||
@ -205,7 +213,7 @@ export const Summary = () => {
|
|||||||
<div className="skills__section__items__wrapper">
|
<div className="skills__section__items__wrapper">
|
||||||
{selectedSkills &&
|
{selectedSkills &&
|
||||||
selectedSkills.map((skill, index) => (
|
selectedSkills.map((skill, index) => (
|
||||||
<span key={skill.id} className="skill_item">
|
<span key={skill.skill_id} className="skill_item">
|
||||||
{skill.skill.name}
|
{skill.skill.name}
|
||||||
{selectedSkills.length > index + 1 && ","}
|
{selectedSkills.length > index + 1 && ","}
|
||||||
</span>
|
</span>
|
||||||
@ -284,7 +292,7 @@ export const Summary = () => {
|
|||||||
<a
|
<a
|
||||||
href={itemGit.link}
|
href={itemGit.link}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noopener noreferrer"
|
||||||
key={itemGit.id}
|
key={itemGit.id}
|
||||||
className="summary__section-git-item git-item"
|
className="summary__section-git-item git-item"
|
||||||
>
|
>
|
||||||
@ -305,7 +313,7 @@ export const Summary = () => {
|
|||||||
className="git-item__link"
|
className="git-item__link"
|
||||||
href={itemGit.link}
|
href={itemGit.link}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<img src={rightArrow} alt="arrowRight" />
|
<img src={rightArrow} alt="arrowRight" />
|
||||||
</a>
|
</a>
|
||||||
|
@ -24,6 +24,7 @@ export const DeveloperPage = () => {
|
|||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/tracker/task/:id" element={<TicketFullScreen />} />
|
<Route exact path="/tracker/task/:id" element={<TicketFullScreen />} />
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path="/tracker/project/:id/task/:taskId"
|
path="/tracker/project/:id/task/:taskId"
|
||||||
|
Reference in New Issue
Block a user