Compare commits
13 Commits
summary_fi
...
15f8b51327
Author | SHA1 | Date | |
---|---|---|---|
15f8b51327 | |||
1d9a47def4 | |||
9909101660 | |||
ca0a509077 | |||
7e64150378 | |||
911b827e41 | |||
104f538e3a | |||
e27da9fca9 | |||
687d9661a3 | |||
3f7bab3353 | |||
dc065f3bdd | |||
a561ed83c4 | |||
268ff58ccd |
3
src/assets/images/VacancyItemImg.svg
Normal file
3
src/assets/images/VacancyItemImg.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.3333 10.6666H4.66667C4.44565 10.6666 4.23369 10.7544 4.07741 10.9107C3.92113 11.067 3.83333 11.2789 3.83333 11.5C3.83333 11.721 3.92113 11.9329 4.07741 12.0892C4.23369 12.2455 4.44565 12.3333 4.66667 12.3333H11.3333C11.5543 12.3333 11.7663 12.2455 11.9226 12.0892C12.0789 11.9329 12.1667 11.721 12.1667 11.5C12.1667 11.2789 12.0789 11.067 11.9226 10.9107C11.7663 10.7544 11.5543 10.6666 11.3333 10.6666ZM11.3333 7.33329H6.33333C6.11232 7.33329 5.90036 7.42109 5.74408 7.57737C5.5878 7.73365 5.5 7.94561 5.5 8.16663C5.5 8.38764 5.5878 8.5996 5.74408 8.75588C5.90036 8.91216 6.11232 8.99996 6.33333 8.99996H11.3333C11.5543 8.99996 11.7663 8.91216 11.9226 8.75588C12.0789 8.5996 12.1667 8.38764 12.1667 8.16663C12.1667 7.94561 12.0789 7.73365 11.9226 7.57737C11.7663 7.42109 11.5543 7.33329 11.3333 7.33329ZM14.6667 2.33329H12.1667V1.49996C12.1667 1.27895 12.0789 1.06698 11.9226 0.910704C11.7663 0.754423 11.5543 0.666626 11.3333 0.666626C11.1123 0.666626 10.9004 0.754423 10.7441 0.910704C10.5878 1.06698 10.5 1.27895 10.5 1.49996V2.33329H8.83333V1.49996C8.83333 1.27895 8.74554 1.06698 8.58926 0.910704C8.43297 0.754423 8.22101 0.666626 8 0.666626C7.77899 0.666626 7.56702 0.754423 7.41074 0.910704C7.25446 1.06698 7.16667 1.27895 7.16667 1.49996V2.33329H5.5V1.49996C5.5 1.27895 5.4122 1.06698 5.25592 0.910704C5.09964 0.754423 4.88768 0.666626 4.66667 0.666626C4.44565 0.666626 4.23369 0.754423 4.07741 0.910704C3.92113 1.06698 3.83333 1.27895 3.83333 1.49996V2.33329H1.33333C1.11232 2.33329 0.900358 2.42109 0.744078 2.57737C0.587797 2.73365 0.5 2.94561 0.5 3.16663V14.8333C0.5 15.4963 0.763392 16.1322 1.23223 16.6011C1.70107 17.0699 2.33696 17.3333 3 17.3333H13C13.663 17.3333 14.2989 17.0699 14.7678 16.6011C15.2366 16.1322 15.5 15.4963 15.5 14.8333V3.16663C15.5 2.94561 15.4122 2.73365 15.2559 2.57737C15.0996 2.42109 14.8877 2.33329 14.6667 2.33329ZM13.8333 14.8333C13.8333 15.0543 13.7455 15.2663 13.5893 15.4225C13.433 15.5788 13.221 15.6666 13 15.6666H3C2.77899 15.6666 2.56702 15.5788 2.41074 15.4225C2.25446 15.2663 2.16667 15.0543 2.16667 14.8333V3.99996H3.83333V4.83329C3.83333 5.05431 3.92113 5.26627 4.07741 5.42255C4.23369 5.57883 4.44565 5.66663 4.66667 5.66663C4.88768 5.66663 5.09964 5.57883 5.25592 5.42255C5.4122 5.26627 5.5 5.05431 5.5 4.83329V3.99996H7.16667V4.83329C7.16667 5.05431 7.25446 5.26627 7.41074 5.42255C7.56702 5.57883 7.77899 5.66663 8 5.66663C8.22101 5.66663 8.43297 5.57883 8.58926 5.42255C8.74554 5.26627 8.83333 5.05431 8.83333 4.83329V3.99996H10.5V4.83329C10.5 5.05431 10.5878 5.26627 10.7441 5.42255C10.9004 5.57883 11.1123 5.66663 11.3333 5.66663C11.5543 5.66663 11.7663 5.57883 11.9226 5.42255C12.0789 5.26627 12.1667 5.05431 12.1667 4.83329V3.99996H13.8333V14.8333Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
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();
|
||||||
|
53
src/components/VacancyItem/VacancyItem.jsx
Normal file
53
src/components/VacancyItem/VacancyItem.jsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import titleImg from "assets/images/VacancyItemImg.svg";
|
||||||
|
|
||||||
|
import "./vacancyItem.scss";
|
||||||
|
|
||||||
|
export const VacancyItem = ({
|
||||||
|
vacancy: { name, description, level, price, location, count }
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="vacancy__item">
|
||||||
|
<div className="vacancy__item__head">
|
||||||
|
<div className="vacancy__item__title">
|
||||||
|
<span className="vacancy__item__img">
|
||||||
|
<img src={titleImg} alt="img" />
|
||||||
|
</span>
|
||||||
|
<h4>{name}</h4>
|
||||||
|
</div>
|
||||||
|
<p className="vacancy__item__description">{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="vacancy__item__block">
|
||||||
|
<div className="vacancy__item__block--left">
|
||||||
|
<div className="vacancy__item__info">
|
||||||
|
<span>Грейд:</span>
|
||||||
|
<p>{level}</p>
|
||||||
|
</div>
|
||||||
|
<div className="vacancy__item__info">
|
||||||
|
<span>Ставка:</span>
|
||||||
|
<p>{price}</p>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
to={"/profile/open-requests/12"}
|
||||||
|
className="vacancy__item__more"
|
||||||
|
>
|
||||||
|
Все требования по вакансии
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="vacancy__item__block--right">
|
||||||
|
<div className="vacancy__item__info">
|
||||||
|
<span>Локация:</span>
|
||||||
|
<p>{location}</p>
|
||||||
|
</div>
|
||||||
|
<div className="vacancy__item__info">
|
||||||
|
<span>Кол-во человек:</span>
|
||||||
|
<p>{count}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button className="vacancy__item__btn">Откликнуться</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
113
src/components/VacancyItem/vacancyItem.scss
Normal file
113
src/components/VacancyItem/vacancyItem.scss
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
.vacancy__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 325px;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 24px 20px 8px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 18px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #2E3A59;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
background: #52B709;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #2E3A59;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 17.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__block {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
top: -12px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&--left {
|
||||||
|
background: #EBEBEB;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px 20px 12px;
|
||||||
|
row-gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
background: #EBEBEB;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px 20px 12px;
|
||||||
|
row-gap: 14px;
|
||||||
|
height: 70%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
color: #000000;
|
||||||
|
font-size: 14px;
|
||||||
|
span {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__more {
|
||||||
|
font-size: 12px;
|
||||||
|
text-decoration: underline;
|
||||||
|
max-width: 97px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #000000;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__btn {
|
||||||
|
position: absolute;
|
||||||
|
max-width: 150px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background: #52B709;
|
||||||
|
border-radius: 44px;
|
||||||
|
right: 5px;
|
||||||
|
padding: 10px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
bottom: 17px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
}
|
17
src/components/VacancyTab/VacancyTab.jsx
Normal file
17
src/components/VacancyTab/VacancyTab.jsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import "./vacancyTab.scss";
|
||||||
|
|
||||||
|
export const VacancyTab = ({ title, active, count, setActive }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
active === title ? "vacancy__tab vacancy__tab--active" : "vacancy__tab"
|
||||||
|
}
|
||||||
|
onClick={setActive}
|
||||||
|
>
|
||||||
|
<p className="vacancy__tab__title">{title}</p>
|
||||||
|
<span className="vacancy__tab__count">{count}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
25
src/components/VacancyTab/vacancyTab.scss
Normal file
25
src/components/VacancyTab/vacancyTab.scss
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.vacancy__tab {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 8px 10px 16px;
|
||||||
|
border: 2px solid white;
|
||||||
|
max-width: 178px;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
color: #2E3A59;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__count {
|
||||||
|
color: #1458DD;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
border: 2px solid #52B709;
|
||||||
|
}
|
||||||
|
}
|
@ -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,13 +1,319 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { Footer } from "@components/Common/Footer/Footer";
|
import { Footer } from "@components/Common/Footer/Footer";
|
||||||
import { Navigation } from "@components/Navigation/Navigation";
|
import { Navigation } from "@components/Navigation/Navigation";
|
||||||
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
|
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
|
||||||
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
|
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
|
||||||
|
import { VacancyItem } from "@components/VacancyItem/VacancyItem";
|
||||||
|
import { VacancyTab } from "@components/VacancyTab/VacancyTab";
|
||||||
|
|
||||||
import "./OpenRequest.scss";
|
import "./OpenRequest.scss";
|
||||||
|
|
||||||
export const OpenRequest = () => {
|
export const OpenRequest = () => {
|
||||||
|
const vacancy = [
|
||||||
|
{
|
||||||
|
name: "Frontend",
|
||||||
|
count: 15,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 1",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 2",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 3",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 4",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 5",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 6",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Backend",
|
||||||
|
count: 8,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 7",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 8",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Дизайн",
|
||||||
|
count: 0,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 9",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 10",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Аналитика",
|
||||||
|
count: 0,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 11",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 12",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 13",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Тестирование",
|
||||||
|
count: 0,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 14",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 15",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior 16",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Laravel Middle+/Senior",
|
||||||
|
description:
|
||||||
|
"Проект представляет из себя монолит с большим техдолгом, нужен php разработчик с опытом распила монолита на модули/микросервисы",
|
||||||
|
level: "Middle+/Senior",
|
||||||
|
location: "РФ, РБ",
|
||||||
|
price: "1500 руб. час",
|
||||||
|
count: "1 сотрудник"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState("Frontend");
|
||||||
return (
|
return (
|
||||||
<div className="open-request">
|
<div className="open-request">
|
||||||
<ProfileHeader />
|
<ProfileHeader />
|
||||||
@ -19,11 +325,34 @@ export const OpenRequest = () => {
|
|||||||
{ name: "Главная", link: "/profile" },
|
{ name: "Главная", link: "/profile" },
|
||||||
{
|
{
|
||||||
name: "Работа в IT открытые запросы",
|
name: "Работа в IT открытые запросы",
|
||||||
link: "/profile/open-request"
|
link: "/profile/open-requests"
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<h2 className="summary__title">Работа в IT открытые запросы</h2>
|
<h2 className="summary__title">Работа в IT открытые запросы</h2>
|
||||||
|
<div className="vacancy__tabs">
|
||||||
|
{vacancy.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<VacancyTab
|
||||||
|
title={item.name}
|
||||||
|
count={item.count}
|
||||||
|
active={activeTab}
|
||||||
|
setActive={() => setActiveTab(item.name)}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="vacancy__items">
|
||||||
|
{vacancy.map((item) => {
|
||||||
|
if (item.name === activeTab) {
|
||||||
|
return item.items.map((vacancy, index) => {
|
||||||
|
return <VacancyItem key={index} vacancy={vacancy} />;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
.open-request {
|
||||||
|
background: #F0F0F0;
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
padding-top: 23px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vacancy {
|
||||||
|
&__tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__items {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
row-gap: 24px;
|
||||||
|
column-gap: 22.5px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
104
src/pages/Vacancy/Vacancy.jsx
Normal file
104
src/pages/Vacancy/Vacancy.jsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { Footer } from "@components/Common/Footer/Footer";
|
||||||
|
import { Navigation } from "@components/Navigation/Navigation";
|
||||||
|
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
|
||||||
|
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
|
||||||
|
|
||||||
|
import titleImg from "assets/images/VacancyItemImg.svg";
|
||||||
|
|
||||||
|
import "./vacancy.scss";
|
||||||
|
|
||||||
|
export const Vacancy = () => {
|
||||||
|
return (
|
||||||
|
<div className="vacancy">
|
||||||
|
<ProfileHeader />
|
||||||
|
<Navigation />
|
||||||
|
<div className="container">
|
||||||
|
<div className="vacancy-content">
|
||||||
|
<ProfileBreadcrumbs
|
||||||
|
links={[
|
||||||
|
{ name: "Главная", link: "/profile" },
|
||||||
|
{
|
||||||
|
name: "Работа в IT открытые запросы",
|
||||||
|
link: "/profile/open-requests"
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<h2 className="opening__title">Laravel Middle+/Senior</h2>
|
||||||
|
<div className="opening">
|
||||||
|
<div className="opening__head">
|
||||||
|
<span className="opening__img">
|
||||||
|
<img src={titleImg} alt="img" />
|
||||||
|
</span>
|
||||||
|
<h4 className="opening__name">
|
||||||
|
Проект представляет из себя монолит с большим техдолгом, нужен
|
||||||
|
php разработчик с опытом распила монолита на модули/микросервисы
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div className="opening__info">
|
||||||
|
<div className="opening__description">
|
||||||
|
<span>Требования :</span>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Опыт разработки на Golang 2+ года и общий опыт разработки 3+
|
||||||
|
года;
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Понимание устройства языка Go (многопоточность, шедулер,
|
||||||
|
кодогенерация);
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Опыт работы с брокерами сообщений (Kafka, RabbitMQ, Nuts и
|
||||||
|
etc);
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Опыт работы с реляционными БД (PostgreSQL, ClickHouse и
|
||||||
|
etc);
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Знание сетевого стека и основных сетевых протоколов на
|
||||||
|
высоком уровне;
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Опыт работы с различными средствами автоматизации для
|
||||||
|
процессов разработки (Nexus, Gitlab registry etc)
|
||||||
|
(необходимо для понимания предметной области);
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Понимание работы прокси и опыт работы с различными решениями
|
||||||
|
(Nginx, Haproxy, Squid).
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="opening__blocks">
|
||||||
|
<div className="opening__block">
|
||||||
|
<div className="opening__block__info">
|
||||||
|
<span>Грейд:</span>
|
||||||
|
<p>Middle+/Senior</p>
|
||||||
|
</div>
|
||||||
|
<div className="opening__block__info">
|
||||||
|
<span>Ставка:</span>
|
||||||
|
<p>1500 руб. час</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="opening__block">
|
||||||
|
<div className="opening__block__info">
|
||||||
|
<span>Локация:</span>
|
||||||
|
<p>РФ, РБ</p>
|
||||||
|
</div>
|
||||||
|
<div className="opening__block__info">
|
||||||
|
<span>Кол-во человек:</span>
|
||||||
|
<p>1 сотрудник</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button className="opening__btn">Откликнуться</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
131
src/pages/Vacancy/vacancy.scss
Normal file
131
src/pages/Vacancy/vacancy.scss
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
.vacancy {
|
||||||
|
background: #F1F1F1;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
padding-top: 23px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.opening {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: white;
|
||||||
|
height: 60px;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 25px;
|
||||||
|
padding: 0 23px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
color: #2E3A59;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
background: #52B709;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
padding: 24px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
position: relative;
|
||||||
|
top: -12px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #000000;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2E3A59;
|
||||||
|
line-height: 17.5px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
li::before {
|
||||||
|
content: '*';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__blocks {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
top: -12px;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__block {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #DDDFE4;
|
||||||
|
background: #EBEBEB;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 24px 21px 12px;
|
||||||
|
row-gap: 14px;
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
font-size: 14px;
|
||||||
|
span {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #000000;
|
||||||
|
margin: 11px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__btn {
|
||||||
|
max-width: 150px;
|
||||||
|
width: 100%;
|
||||||
|
background: #52B709;
|
||||||
|
border-radius: 44px;
|
||||||
|
height: 40px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 14px;
|
||||||
|
border: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 25%;
|
||||||
|
bottom: -40%;
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import { QuizReportPage } from "@pages/Quiz/QuizReportPage";
|
|||||||
import Statistics from "@pages/Statistics/Statistics";
|
import Statistics from "@pages/Statistics/Statistics";
|
||||||
import { Summary } from "@pages/Summary/Summary";
|
import { Summary } from "@pages/Summary/Summary";
|
||||||
import { Tracker } from "@pages/Tracker/Tracker";
|
import { Tracker } from "@pages/Tracker/Tracker";
|
||||||
|
import { Vacancy } from "@pages/Vacancy/Vacancy";
|
||||||
import { ViewReport } from "@pages/ViewReport/ViewReport";
|
import { ViewReport } from "@pages/ViewReport/ViewReport";
|
||||||
|
|
||||||
import TicketFullScreen from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
|
import TicketFullScreen from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
|
||||||
@ -23,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"
|
||||||
@ -36,6 +38,7 @@ export const DeveloperPage = () => {
|
|||||||
<Route exact path="calendar/report" element={<ReportForm />} />
|
<Route exact path="calendar/report" element={<ReportForm />} />
|
||||||
<Route exact path="calendar/view/:date/:id" element={<ViewReport />} />
|
<Route exact path="calendar/view/:date/:id" element={<ViewReport />} />
|
||||||
<Route exact path="open-requests" element={<OpenRequest />} />
|
<Route exact path="open-requests" element={<OpenRequest />} />
|
||||||
|
<Route exact path="open-requests/:id" element={<Vacancy />} />
|
||||||
<Route exact path="summary" element={<Summary />} />
|
<Route exact path="summary" element={<Summary />} />
|
||||||
<Route exact path="tracker" element={<Tracker />} />
|
<Route exact path="tracker" element={<Tracker />} />
|
||||||
<Route exact path="statistics/:id" element={<Statistics />} />
|
<Route exact path="statistics/:id" element={<Statistics />} />
|
||||||
|
Reference in New Issue
Block a user