2 Commits

Author SHA1 Message Date
988b5e65b0 employees table 2024-07-26 20:07:43 +03:00
a6981f90b2 employees table 2024-07-26 20:07:35 +03:00
23 changed files with 372 additions and 455 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -24,35 +24,19 @@ 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 <a href="https://www.vk.com/">
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 <a href="https://www.telegram.org/">
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 <a href="mailto:office@itguild.info">office@itguild.info</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="#" target="_blank" rel="noopener noreferrer"> <a href="#">Присоединиться к команде</a>
Присоединиться к команде
</a>
</div> </div>
<p> <p>
© {new Date().getFullYear()} - Outstaffing. Все права защищены © {new Date().getFullYear()} - Outstaffing. Все права защищены

View File

@ -6,7 +6,6 @@ import empty from "assets/images/emptyPage.svg";
import "./emptyBlock.scss"; import "./emptyBlock.scss";
export const EmptyBlock = () => { export const EmptyBlock = () => {
return ( return (
<> <>
<div className="empty-block"> <div className="empty-block">
@ -21,4 +20,3 @@ export const EmptyBlock = () => {
</> </>
); );
}; };

View File

@ -122,6 +122,15 @@ 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 = () => {
@ -301,17 +310,6 @@ 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",
@ -382,111 +380,82 @@ export const ModalTiсket = ({
} }
useEffect(() => { useEffect(() => {
if (active) { initListeners();
setStartDate(task.dead_line ? new Date(task.dead_line) : new Date()); apiRequest(
setTaskPriority(task.execution_priority); `/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
setMembers(task.taskUsers); ).then((res) => {
setTaskTags(task.mark); const comments = res.reduce((acc, cur) => {
setExecutorId(task.executor_id); if (!cur.parent_id) {
setDeadLine(task.dead_line); acc.push({ ...cur, subComments: [] });
setExecutor(task.executor);
setInputsValue({
title: task.title,
description: task.description,
comment: ""
});
initListeners();
apiRequest(
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
).then((res) => {
const comments = res.reduce((acc, cur) => {
if (!cur.parent_id) {
acc.push({ ...cur, subComments: [] });
} else {
acc.forEach((item) => {
if (item.id === cur.parent_id) item.subComments.push(cur);
});
}
return acc;
}, []);
setComments(comments);
});
apiRequest(
`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`
).then((res) => {
if (Array.isArray(res)) {
let timerSeconds = 0;
res.length &&
res.forEach((time) => {
timerSeconds += time.deltaSeconds;
setCurrentTimerCount({
hours: Math.floor(timerSeconds / 60 / 60),
minute: Math.floor((timerSeconds / 60) % 60),
seconds: timerSeconds % 60
});
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
updateTimerSec = timerSeconds % 60;
if (!time.stopped_at) {
setTimerStart(true);
startTimer();
setTimerInfo(time);
}
});
} else { } else {
setCurrentTimerCount({ acc.forEach((item) => {
hours: 0, if (item.id === cur.parent_id) item.subComments.push(cur);
minute: 0,
seconds: 0
}); });
} }
}); return acc;
}, []);
setComments(comments);
});
apiRequest(`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
(res) => {
let timerSeconds = 0;
res.length &&
res.forEach((time) => {
timerSeconds += time.deltaSeconds;
setCurrentTimerCount({
hours: Math.floor(timerSeconds / 60 / 60),
minute: Math.floor((timerSeconds / 60) % 60),
seconds: timerSeconds % 60
});
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
updateTimerSec = timerSeconds % 60;
if (!time.stopped_at) {
setTimerStart(true);
startTimer();
setTimerInfo(time);
}
});
}
);
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" &&
Array.isArray(correctProjectUsers) && Boolean(
!correctProjectUsers.find( !correctProjectUsers.find(
(item) => item.user_id === profileInfo.id_user (item) => item.user_id === profileInfo.id_user
) )
) { )
setCorrectProjectUsers((prevState) => [ ) {
...prevState, setCorrectProjectUsers((prevState) => [
{ ...prevState,
user: { {
avatar: profileInfo.photo, user: {
fio: profileInfo.fio avatar: profileInfo.photo,
}, fio: profileInfo.fio
user_id: profileInfo.id_user },
} user_id: profileInfo.id_user
]); }
} ]);
} }
}, [active]); }, []);
useEffect(() => { useEffect(() => {
if (Array.isArray(taskTags)) { let tagIds = taskTags.map((tag) => tag.id);
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) {
@ -565,15 +534,13 @@ export const ModalTiсket = ({
} }
useEffect(() => { useEffect(() => {
if (Array.isArray(members)) { let ids = members.map((user) => user.user_id);
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() {
@ -717,7 +684,6 @@ export const ModalTiсket = ({
editor={ClassicEditor} editor={ClassicEditor}
data={inputsValue.description} data={inputsValue.description}
config={{ config={{
toolbar: ["link"],
removePlugins: [ removePlugins: [
"CKFinderUploadAdapter", "CKFinderUploadAdapter",
"CKFinder", "CKFinder",
@ -729,10 +695,7 @@ 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();
@ -750,7 +713,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 (
@ -910,7 +873,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">
@ -1042,24 +1005,23 @@ 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">
{Array.isArray(taskTags) && {taskTags.map((tag) => {
taskTags.map((tag) => { return (
return ( <div
<div className="tags__selected__item"
className="tags__selected__item" key={tag.id}
key={tag.id} style={{ background: tag.color }}
style={{ background: tag.color }} >
> <p>{tag.slug}</p>
<p>{tag.slug}</p> <img
<img src={crossWhite}
src={crossWhite} className="delete"
className="delete" alt="delete"
alt="delete" onClick={() => deleteTagFromTask(tag.id)}
onClick={() => deleteTagFromTask(tag.id)} />
/> </div>
</div> );
); })}
})}
</div> </div>
<div <div
className="tags__select" className="tags__select"

View File

@ -625,10 +625,7 @@ 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();

View File

@ -62,14 +62,10 @@ export const SideBar = () => {
<Link to={"/forms"}>Формы</Link> <Link to={"/forms"}>Формы</Link>
</li> </li>
<li> <li>
<a href="#" target="_blank" rel="noopener noreferrer"> <a href="#">Школа</a>
Школа
</a>
</li> </li>
<li> <li>
<a href="#" target="_blank" rel="noopener noreferrer"> <a href="#">Контакты</a>
Контакты
</a>
</li> </li>
<li> <li>
<Link to={"/blog"}>Блог</Link> <Link to={"/blog"}>Блог</Link>

View File

@ -1,4 +1,4 @@
import React, { forwardRef, useEffect, useState } from "react"; import React, { 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,181 +14,173 @@ import avatarMok from "assets/images/avatarMok.webp";
import "./trackerCardTask.scss"; import "./trackerCardTask.scss";
const TrackerCardTask = forwardRef( const TrackerCardTask = ({
( task,
{ projectBoard,
task, titleColor,
projectBoard, column,
titleColor, openTicket,
column, startWrapperIndexTest,
openTicket, setWrapperHover
startWrapperIndexTest, }) => {
setWrapperHover const dispatch = useDispatch();
}, const [taskHover, setTaskHover] = useState({});
ref
) => {
const dispatch = useDispatch();
const [taskHover, setTaskHover] = useState({});
const priority = { const priority = {
2: "Высокий", 2: "Высокий",
1: "Средний", 1: "Средний",
0: "Низкий" 0: "Низкий"
}; };
const priorityClass = { const priorityClass = {
2: "high", 2: "high",
1: "middle", 1: "middle",
0: "low" 0: "low"
}; };
function dragDropTaskHandler(e, task, column) { function dragDropTaskHandler(e, task, column) {
e.preventDefault(); e.preventDefault();
if (task.id === startWrapperIndexTest.current.task.id) { if (task.id === startWrapperIndexTest.current.task.id) {
return; return;
}
const finishTask = column.tasks.indexOf(task);
dispatch(
movePositionProjectTask({
startTask: startWrapperIndexTest.current.task,
finishTask: task,
finishIndex: finishTask
})
);
} }
function dragOverTaskHandler(e, task) { const finishTask = column.tasks.indexOf(task);
e.preventDefault();
if (startWrapperIndexTest.current.task.id === task.id) {
return;
}
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
}
function dragStartHandler(e, task, columnId) { dispatch(
startWrapperIndexTest.current = { task: task, index: columnId }; movePositionProjectTask({
} startTask: startWrapperIndexTest.current.task,
finishTask: task,
function dragLeaveTaskHandler() { finishIndex: finishTask
setTaskHover((prevState) => ({ [prevState]: false })); })
}
function dragEndTaskHandler() {
setTaskHover((prevState) => ({ [prevState]: false }));
setWrapperHover((prevState) => ({
[prevState]: false
}));
}
useEffect(() => {
const tasksHover = {};
const columnHover = {};
if (Object.keys(projectBoard).length) {
projectBoard.columns.forEach((column) => {
columnHover[column.id] = false;
column.tasks.forEach((task) => (tasksHover[task.id] = false));
});
}
setWrapperHover(columnHover);
setTaskHover(tasksHover);
}, [projectBoard]);
return (
<div
ref={ref}
key={task.id}
className={`tasks__board__item ${
taskHover[task.id] ? "task__hover" : ""
}`}
draggable={true}
onDragStart={(e) => dragStartHandler(e, task, column.id)}
onDragOver={(e) => dragOverTaskHandler(e, task)}
onDragLeave={(e) => dragLeaveTaskHandler(e)}
onDragEnd={() => dragEndTaskHandler()}
onDrop={(e) => dragDropTaskHandler(e, task, column)}
onClick={() => openTicket(task)}
>
<div className="tasks__board__item__title">
<p className="task__board__item__title">{task.title}</p>
</div>
<p
dangerouslySetInnerHTML={{
__html: task.description
}}
className="tasks__board__item__description"
></p>
{Boolean(task.mark.length) && (
<div className="tasks__board__item__tags">
{task.mark.map((tag) => {
return (
<div
className="tag-item"
key={tag.id}
style={{ background: tag.color }}
>
<p>{tag.slug}</p>
</div>
);
})}
</div>
)}
<div className="tasks__board__item__container">
{typeof task.execution_priority === "number" && (
<div className="tasks__board__item__priority">
<p></p>
<span className={priorityClass[task.execution_priority]}>
{priority[task.execution_priority]}
</span>
</div>
)}
{task.dead_line && (
<div className="tasks__board__item__dead-line">
<p></p>
<span style={{ color: titleColor }}>
{getCorrectDate(task.dead_line)}
</span>
</div>
)}
</div>
<div className="tasks__board__item__info">
<div className="tasks__board__item__executor">
<img
src={
task.executor?.avatar
? urlForLocal(task.executor?.avatar)
: avatarMok
}
alt="avatar"
/>
<span>
{removeLast(task.executor?.fio) || "Исполнитель не назначен"}
</span>
</div>
<div className="tasks__board__item__info__tags">
<div className="tasks__board__item__info__more">
<img src={commentsBoard} alt="commentsImg" />
<span>{task.comment_count}</span>
</div>
<div className="tasks__board__item__info__more">
<img src={filesBoard} alt="filesImg" />
<span>{task.file_count}</span>
</div>
</div>
</div>
<TrackerSelectColumn
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
currentColumn={column}
task={task}
/>
</div>
); );
} }
);
TrackerCardTask.displayName = "TrackerCardTask"; function dragOverTaskHandler(e, task) {
e.preventDefault();
if (startWrapperIndexTest.current.task.id === task.id) {
return;
}
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
}
function dragStartHandler(e, task, columnId) {
startWrapperIndexTest.current = { task: task, index: columnId };
}
function dragLeaveTaskHandler() {
setTaskHover((prevState) => ({ [prevState]: false }));
}
function dragEndTaskHandler() {
setTaskHover((prevState) => ({ [prevState]: false }));
setWrapperHover((prevState) => ({
[prevState]: false
}));
}
useEffect(() => {
const tasksHover = {};
const columnHover = {};
if (Object.keys(projectBoard).length) {
projectBoard.columns.forEach((column) => {
columnHover[column.id] = false;
column.tasks.forEach((task) => (tasksHover[task.id] = false));
});
}
setWrapperHover(columnHover);
setTaskHover(tasksHover);
}, [projectBoard]);
return (
<div
key={task.id}
className={`tasks__board__item ${
taskHover[task.id] ? "task__hover" : ""
}`}
draggable={true}
onDragStart={(e) => dragStartHandler(e, task, column.id)}
onDragOver={(e) => dragOverTaskHandler(e, task)}
onDragLeave={(e) => dragLeaveTaskHandler(e)}
onDragEnd={() => dragEndTaskHandler()}
onDrop={(e) => dragDropTaskHandler(e, task, column)}
onClick={(e) => openTicket(e, task)}
>
<div className="tasks__board__item__title">
<p className="task__board__item__title">{task.title}</p>
</div>
<p
dangerouslySetInnerHTML={{
__html: task.description
}}
className="tasks__board__item__description"
></p>
{Boolean(task.mark.length) && (
<div className="tasks__board__item__tags">
{task.mark.map((tag) => {
return (
<div
className="tag-item"
key={tag.id}
style={{ background: tag.color }}
>
<p>{tag.slug}</p>
</div>
);
})}
</div>
)}
<div className="tasks__board__item__container">
{typeof task.execution_priority === "number" && (
<div className="tasks__board__item__priority">
<p></p>
<span className={priorityClass[task.execution_priority]}>
{priority[task.execution_priority]}
</span>
</div>
)}
{task.dead_line && (
<div className="tasks__board__item__dead-line">
<p></p>
<span style={{ color: titleColor }}>
{getCorrectDate(task.dead_line)}
</span>
</div>
)}
</div>
<div className="tasks__board__item__info">
<div className="tasks__board__item__executor">
<img
src={
task.executor?.avatar
? urlForLocal(task.executor?.avatar)
: avatarMok
}
alt="avatar"
/>
<span>
{removeLast(task.executor?.fio) || "Исполнитель не назначен"}
</span>
</div>
<div className="tasks__board__item__info__tags">
<div className="tasks__board__item__info__more">
<img src={commentsBoard} alt="commentsImg" />
<span>{task.comment_count}</span>
</div>
<div className="tasks__board__item__info__more">
<img src={filesBoard} alt="filesImg" />
<span>{task.file_count}</span>
</div>
</div>
</div>
<TrackerSelectColumn
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
currentColumn={column}
task={task}
/>
</div>
);
};
export default TrackerCardTask; export default TrackerCardTask;

View File

@ -121,7 +121,6 @@ export const TrackerTaskComment = ({
editor={ClassicEditor} editor={ClassicEditor}
data={commentsEditText} data={commentsEditText}
config={{ config={{
toolbar: ["link"],
removePlugins: [ removePlugins: [
"CKFinderUploadAdapter", "CKFinderUploadAdapter",
"CKFinder", "CKFinder",
@ -133,10 +132,7 @@ 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();

View File

@ -90,11 +90,7 @@ export const FormPage = () => {
Заявка на собеседование через телеграм Заявка на собеседование через телеграм
</div> </div>
<div className="form-page__telegram-icon"> <div className="form-page__telegram-icon">
<a <a href="https://t.me/st0kir" target="_blank" rel="noreferrer">
href="https://t.me/st0kir"
target="_blank"
rel="noopener noreferrer"
>
<SVG src={telegramIcon} /> <SVG src={telegramIcon} />
</a> </a>
</div> </div>

View File

@ -13,10 +13,6 @@ 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";
@ -33,22 +29,22 @@ export const Landing = () => {
{ {
name: "<span>Найти</span> работу <br/> в IT", name: "<span>Найти</span> работу <br/> в IT",
path: "/stack", path: "/stack",
img: searchIT img: cat
}, },
{ {
name: "<span>Система</span> контроля версий GIT", name: "<span>Система</span> контроля версий GIT",
path: "/stack", path: "/stack",
img: systemControlGit img: cat
}, },
{ {
name: "<span>Управление</span> задачами", name: "<span>Управление</span> задачами",
path: "/landing-tracker", path: "/landing-tracker",
img: taskManagement img: cat
}, },
{ {
name: "<span>Система</span> для отчётности", name: "<span>Система</span> для отчётности",
path: "/stack", path: "/stack",
img: reportingSystem img: cat
}, },
{ {
name: "Все наши предложения", name: "Все наши предложения",

View File

@ -12,7 +12,6 @@ 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";
@ -174,9 +173,9 @@ export const LandingTracker = () => {
); );
})} })}
</div> </div>
<div className="goals__target"> {/* <div className="steps__portfolio">
<img src={target} alt="target" /> <img src={portfolio} alt="portfolio" />
</div> </div> */}
</div> </div>
</section> </section>

View File

@ -446,11 +446,6 @@
} }
} }
} }
&__target {
position: absolute;
bottom: 0;
}
} }
} }

View File

@ -46,6 +46,7 @@ export const PartnerCategories = () => {
const theme = useTheme(getTheme()); const theme = useTheme(getTheme());
const [nodes, setNodes] = useState([]); const [nodes, setNodes] = useState([]);
const [initialNodes, setInitialNodes] = useState([]); const [initialNodes, setInitialNodes] = useState([]);
const [activeTab, setActiveTab] = useState("Все");
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
@ -308,10 +309,38 @@ export const PartnerCategories = () => {
/> />
</label> </label>
<div className="table__tabs"> <div className="table__tabs">
<div className="table__tab">Все</div> <div
onClick={() => {
setActiveTab("Все");
setNodes(initialNodes);
}}
className={
activeTab === "Все"
? "table__tab table__tab--active"
: "table__tab"
}
>
Все
</div>
{tabs.map((tab) => { {tabs.map((tab) => {
return ( return (
<div className="table__tab" key={tab.value}> <div
onClick={() => {
setActiveTab(tab.name);
setNodes(
initialNodes.filter(
(item) =>
item.resume.userCard.position_id === tab.value
)
);
}}
className={
activeTab === tab.name
? "table__tab table__tab--active"
: "table__tab"
}
key={tab.value}
>
{tab.name} {tab.name}
</div> </div>
); );

View File

@ -189,6 +189,25 @@
border-radius: 5px; border-radius: 5px;
} }
&__tab {
padding: 8px 12px;
cursor: pointer;
color: rgba(46, 58, 89, 1);
font-size: 15px;
&--active {
background: rgba(255, 255, 255, 1);
font-size: 16px;
border-radius: 5px;
border: 0;
}
&:nth-child(2) {
border-right: 1px solid rgba(224, 226, 229, 1);
border-left: 1px solid rgba(224, 226, 229, 1);
}
}
&__avatar { &__avatar {
width: 40px; width: 40px;
height: 40px; height: 40px;

View File

@ -1,10 +1,10 @@
import React from "react"; import React from "react";
import { Footer } from "@components/Common/Footer/Footer"; import { Footer } from "@components/Common/Footer/Footer";
import { Navigation } from "@components/Navigation/Navigation";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { EmptyBlock } from "@components/EmptyBlock/EmptyBlock"; import { EmptyBlock } from "@components/EmptyBlock/EmptyBlock";
import { Navigation } from "@components/Navigation/Navigation";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import "./payouts.scss"; import "./payouts.scss";
@ -17,7 +17,7 @@ export const Payouts = () => {
<ProfileBreadcrumbs <ProfileBreadcrumbs
links={[ links={[
{ name: "Главная", link: "/profile" }, { name: "Главная", link: "/profile" },
{ name: "Выплаты и финансы ", link: "/profile/payouts" }, { name: "Выплаты и финансы ", link: "/profile/payouts" }
]} ]}
/> />
<h3 className="payouts__title">Выплаты и финансы </h3> <h3 className="payouts__title">Выплаты и финансы </h3>

View File

@ -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, useLocation, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { import {
activeLoader, activeLoader,
@ -51,9 +51,6 @@ 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);
@ -81,19 +78,6 @@ 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) {
@ -161,32 +145,21 @@ export const ProjectTracker = () => {
setPriorityTask(length); setPriorityTask(length);
} }
const updateUrlWithTaskId = (taskId) => { function openTicket(e, task) {
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);
updateUrlWithTaskId(task.id); const currentUrl = window.location.pathname;
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", {
@ -448,16 +421,19 @@ export const ProjectTracker = () => {
</Link> </Link>
</div> </div>
</div> </div>
<ModalTicket
active={modalActiveTicket} {Boolean(modalActiveTicket) && (
setActive={setModalActiveTicket} <ModalTicket
task={selectedTicket} active={modalActiveTicket}
projectId={projectBoard.id} setActive={setModalActiveTicket}
projectName={projectBoard.name} task={selectedTicket}
projectUsers={projectBoard.projectUsers} projectId={projectBoard.id}
projectOwnerId={projectBoard.owner_id} projectName={projectBoard.name}
projectMarks={projectBoard.mark} projectUsers={projectBoard.projectUsers}
/> projectOwnerId={projectBoard.owner_id}
projectMarks={projectBoard.mark}
/>
)}
<div className="tasks__container"> <div className="tasks__container">
{Boolean(projectBoard?.columns) && {Boolean(projectBoard?.columns) &&
@ -559,9 +535,6 @@ export const ProjectTracker = () => {
startWrapperIndexTest={startWrapperIndexTest} startWrapperIndexTest={startWrapperIndexTest}
task={task} task={task}
titleColor={titleColor} titleColor={titleColor}
ref={(el) => {
taskRefs.current[task.id] = el;
}}
/> />
); );
})} })}

View File

@ -648,15 +648,9 @@ export const Stack = () => {
onChange={handleChange} onChange={handleChange}
/> />
<p> <p>
Соглашаюсь с{" "} Соглашаюсь с <a href="">Пользовательским соглашением</a> и
<a href="" target="_blank" rel="noopener noreferrer">
Пользовательским соглашением
</a>{" "}
и
<br /> <br />
<a href="" target="_blank" rel="noopener noreferrer"> <a href="">Политикой обработки данных</a>
Политикой обработки данных
</a>
</p> </p>
</div> </div>

View File

@ -58,25 +58,6 @@ 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",
@ -176,7 +157,13 @@ export const Summary = () => {
<img <img
src={deleteIcon} src={deleteIcon}
alt="deleteIcon" alt="deleteIcon"
onClick={() => deleteSkill(skill)} onClick={() =>
setSelectedSkills((prevValue) =>
prevValue.filter(
(item) => item.skill_id !== skill.skill_id
)
)
}
/> />
</span> </span>
); );
@ -197,7 +184,12 @@ export const Summary = () => {
{skillsList.map((skill) => { {skillsList.map((skill) => {
return ( return (
<p <p
onClick={() => addSkill(skill)} onClick={() =>
setSelectedSkills((prevValue) => [
...prevValue,
{ skill: skill, skill_id: skill.id }
])
}
key={skill.id} key={skill.id}
className="select-skills__item" className="select-skills__item"
> >
@ -213,7 +205,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.skill_id} className="skill_item"> <span key={skill.id} className="skill_item">
{skill.skill.name} {skill.skill.name}
{selectedSkills.length > index + 1 && ","} {selectedSkills.length > index + 1 && ","}
</span> </span>
@ -292,7 +284,7 @@ export const Summary = () => {
<a <a
href={itemGit.link} href={itemGit.link}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noreferrer"
key={itemGit.id} key={itemGit.id}
className="summary__section-git-item git-item" className="summary__section-git-item git-item"
> >
@ -313,7 +305,7 @@ export const Summary = () => {
className="git-item__link" className="git-item__link"
href={itemGit.link} href={itemGit.link}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noreferrer"
> >
<img src={rightArrow} alt="arrowRight" /> <img src={rightArrow} alt="arrowRight" />
</a> </a>

View File

@ -24,7 +24,6 @@ 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"