20 Commits

Author SHA1 Message Date
4464324ae2 developer resume 2024-08-07 18:06:10 +03:00
4cd3118649 developer resume 2024-08-07 18:06:03 +03:00
16e3a2649d LandingTracker adaptive 2024-08-07 12:25:55 +03:00
b61c9ba58a add telegram token(bot) in PartnerSettings 2024-08-06 16:42:45 +03:00
d75507ea46 fix links in AuthHeader 2024-08-02 14:06:23 +03:00
b02eff466f fix adaptive 2024-08-02 13:48:08 +03:00
a76725edf5 fix adaptive Calendar 2024-08-01 12:23:17 +03:00
5cdf072551 fix LandingTracker and add routes 2024-07-31 15:05:52 +03:00
9771d2a602 add ModalAuth 2024-07-30 15:51:29 +03:00
0a8ed604a0 small edits 2024-07-29 16:12:38 +03:00
4084c52a9b Merge pull request 'page_under_construction' (#40) from page_under_construction into main
Reviewed-on: #40
2024-07-26 20:10:26 +03:00
b6a4ff6652 Merge pull request 'page_under_construction' (#39) from page_under_construction into main
Reviewed-on: #39
2024-07-26 20:07:30 +03:00
15f8b51327 fix openening a task by link 2024-07-26 15:50:28 +03:00
1d9a47def4 landing add images opportunities 2024-07-26 15:31:24 +03:00
9909101660 fix Summary skills 2024-07-26 15:22:53 +03:00
ca0a509077 fix ModalTicket logic 2024-07-25 18:17:39 +03:00
7e64150378 fix scss __target in LandingTracker 2024-07-25 18:16:52 +03:00
911b827e41 add target.webp in LandingTracker 2024-07-25 11:43:52 +03:00
104f538e3a fix CKEditor links 2024-07-23 13:34:05 +03:00
e27da9fca9 fix external links 2024-07-22 12:05:32 +03:00
47 changed files with 1408 additions and 484 deletions

View File

@ -0,0 +1,4 @@
<svg width="40" height="41" viewBox="0 0 40 41" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 12.5C0 5.87258 5.37258 0.5 12 0.5H28C34.6274 0.5 40 5.87258 40 12.5V28.5C40 35.1274 34.6274 40.5 28 40.5H12C5.37258 40.5 0 35.1274 0 28.5V12.5Z" fill="#F0F4FA"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.4809 14.1916C26.6868 14.105 26.9122 14.0751 27.1336 14.1051C27.355 14.1351 27.5643 14.2239 27.7398 14.3622C27.9152 14.5006 28.0504 14.6834 28.1312 14.8917C28.212 15.1 28.2355 15.3262 28.1992 15.5466L26.3092 27.0108C26.1259 28.1166 24.9125 28.7508 23.8984 28.2C23.05 27.7391 21.79 27.0291 20.6567 26.2883C20.09 25.9175 18.3542 24.73 18.5675 23.885C18.7509 23.1625 21.6675 20.4475 23.3342 18.8333C23.9884 18.1991 23.69 17.8333 22.9175 18.4166C20.9984 19.865 17.9192 22.0675 16.9009 22.6875C16.0025 23.2341 15.5342 23.3275 14.9742 23.2341C13.9525 23.0641 13.005 22.8008 12.2317 22.48C11.1867 22.0466 11.2375 20.61 12.2309 20.1916L26.4809 14.1916Z" fill="#7992B2"/>
</svg>

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -10,7 +10,6 @@ import { apiRequest } from "@api/request";
import { Loader } from "@components/Common/Loader/Loader";
import ModalErrorLogin from "@components/Modal/ModalErrorLogin/ModalErrorLogin";
import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration";
import ModalResetPassword from "@components/Modal/ModalResetPassword/ModalResetPassword";
import authHead from "assets/icons/authHead.svg";
@ -30,7 +29,6 @@ export const AuthBox = ({ title }) => {
const [error, setError] = useState(null);
const [modalError, setModalError] = useState(false);
const [modalReset, setModalReset] = useState(false);
const [modalReg, setModalReg] = useState(false);
const [showPassword, setShowPassword] = useState(false);
useEffect(() => {
@ -128,19 +126,7 @@ export const AuthBox = ({ title }) => {
Восстановить пароль
</span>
<ModalResetPassword active={modalReset} setActive={setModalReset} />
<ModalRegistration active={modalReg} setActive={setModalReg} />
</div>
<p className="auth-box__registration">
У вас ещё нет аккаунта? &nbsp;
<span
onClick={(e) => {
e.preventDefault();
setModalReg(true);
}}
>
Зарегистрироваться
</span>
</p>
</form>
</div>
);

View File

@ -117,25 +117,45 @@
}
&__body {
div {
&__week-days {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
@media (max-width: 680px) {
display: none;
}
p {
color: #9babc5;
font-size: 14px;
font-weight: 500;
text-align: center;
}
&-mobile {
display: none;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
@media (max-width: 680px) {
display: grid;
}
p {
color: #9babc5;
font-size: 14px;
font-weight: 500;
text-align: center;
}
}
}
margin: 20px 0 20px;
}
&__form {
display: flex;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(7, 1fr);
justify-content: space-between;
button {
@ -153,7 +173,7 @@
.form-date {
width: 100%;
padding: 5px 0 0 15px;
padding: 5px 0 0 0;
height: 100%;
}
@ -205,12 +225,10 @@
@media (max-width: 550px) {
width: 60px;
height: 35px;
}
@media (max-width: 450px) {
width: 45px;
height: 35px;
}
}
}
@ -265,6 +283,11 @@
}
.form-box {
background-color: #fafbfe;
padding: 0 10px;
@media (max-width: 450px) {
padding: 0;
}
.form-hours {
color: #6dd077;
@ -284,6 +307,11 @@
font-weight: 700;
font-size: 14px;
margin: auto;
@media (max-width: 680px) {
font-weight: 700;
font-size: 10px;
}
}
}
.form-hours::before {

View File

@ -4,6 +4,8 @@ import { Link, NavLink } from "react-router-dom";
import { BurgerButton } from "@components/BurgerMenu/burgerButton";
import { BurgerMenu } from "@components/BurgerMenu/burgerMenu";
import ModalAuth from "@components/Modal/ModalAuth/ModalAuth";
import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration";
import authIcon from "assets/icons/authIcon.svg";
@ -11,15 +13,23 @@ import "./authHeader.scss";
export const AuthHeader = () => {
const [actionMenu, setActionMenu] = useState(false);
const [modalReg, setModalReg] = useState(false);
const [modalAuth, setModalAuth] = useState(false);
return (
<div className="auth-header">
<BurgerMenu active={actionMenu} />
<ModalRegistration active={modalReg} setActive={setModalReg} />
<ModalAuth active={modalAuth} setActive={setModalAuth} />
<div className="auth-header__navigation">
<div className="auth__logo">
<div>
<BurgerButton active={actionMenu} setActive={setActionMenu} />
</div>
<h3>IT GUILD</h3>
<NavLink to={"/"}>
<h3>IT GUILD</h3>
</NavLink>
<div>
<Link to="/auth">
<SVG src={authIcon} />
@ -29,28 +39,34 @@ export const AuthHeader = () => {
<div className="auth-nav">
<ul>
<li>
<NavLink to={"/auth"}>кейсы</NavLink>
<NavLink to={"/stack"}>аутстафинг</NavLink>
</li>
<li>
<NavLink to={"/stack"}>стек</NavLink>
<NavLink to={"/tracker-intro"}>трекер</NavLink>
</li>
<li>
<NavLink to={"/tracker-intro"}>как это работает</NavLink>
</li>
<li>
<NavLink to={"/auth-candidate"}>отзывы</NavLink>
</li>
<li>
<NavLink to={"/profile"}>наши продукты</NavLink>
<NavLink to={"/auth-candidate"}>работа в IT</NavLink>
</li>
</ul>
</div>
<div className="auth__buttons">
<button className="signIn">
<Link to="/auth">войти</Link>
<button
className="signIn"
onClick={(e) => {
e.preventDefault();
setModalAuth(true);
}}
>
войти
</button>
<button className="signUp">
<Link to="/auth">регистрация</Link>
<button
className="signUp"
onClick={(e) => {
e.preventDefault();
setModalReg(true);
}}
>
регистрация
</button>
</div>
</div>

View File

@ -130,9 +130,7 @@
}
.signUp {
a {
color: #a7ca60;
}
color: #a7ca60;
border: 1px solid #a7ca60;
background: none;

View File

@ -24,19 +24,35 @@ export const Footer = () => {
<div className="footer__bottom">
<div className="footer__social">
<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} />
</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} />
</a>
</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 className="footer__info">
<div className="footer__mail">
{/* <img src={email} alt="email" /> */}
<a href="#">Присоединиться к команде</a>
<a href="#" target="_blank" rel="noopener noreferrer">
Присоединиться к команде
</a>
</div>
<p>
© {new Date().getFullYear()} - Outstaffing. Все права защищены

View File

@ -119,6 +119,10 @@
.create-ticket-project {
padding: 0;
background: white;
@media (max-width: 770px) {
width: 90%;
}
}
.ck-editor {

View File

@ -0,0 +1,124 @@
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { loading, selectIsLoading } from "@redux/loaderSlice";
import { auth, setUserInfo } from "@redux/outstaffingSlice";
import { setRole } from "@redux/roleSlice";
import { apiRequest } from "@api/request";
// import { useNotification } from "@hooks/useNotification";
import BaseButton from "@components/Common/BaseButton/BaseButton";
import { Loader } from "@components/Common/Loader/Loader";
import ModalLayout from "@components/Common/ModalLayout/ModalLayout";
import "./modalAuth.scss";
export const ModalAuth = ({ active, setActive }) => {
const navigate = useNavigate();
const dispatch = useDispatch();
const isLoading = useSelector(selectIsLoading);
const [error, setError] = useState(null);
const [modalError, setModalError] = useState(false);
const [formData, setFormData] = useState({
email: "",
password: ""
});
const closeModal = () => {
setActive(false);
};
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
};
const submitHandler = () => {
if (!isLoading) {
dispatch(loading(true));
apiRequest("/user/login", {
method: "POST",
data: formData
}).then((res) => {
if (!res.access_token) {
setError("Введены некорректные данные для входа");
setModalError(true);
dispatch(loading(false));
} else {
localStorage.setItem("auth_token", res.access_token);
localStorage.setItem("id", res.id);
localStorage.setItem("cardId", res.card_id);
localStorage.setItem("role_status", res.status);
localStorage.setItem(
"access_token_expired_at",
res.access_token_expired_at
);
dispatch(auth(true));
dispatch(setUserInfo(res));
dispatch(loading(false));
dispatch(setRole("ROLE_PARTNER"));
navigate("/profile");
}
});
}
};
return (
<ModalLayout active={active} setActive={closeModal} styles={"auth"}>
<div className="auth-body__main">
<h2 className="auth-body__main-title">
Войти к <span>ITguild</span>
</h2>
<div className="input-body">
<div className="input-body__box">
<div className="input-container">
<h5>E-mail</h5>
<input
type="email"
name="email"
onChange={handleChange}
value={formData.email}
placeholder="Почта"
id="authEmail"
/>
</div>
</div>
<div className="input-body__box">
<div className="input-container">
<h5>Пароль</h5>
<input
type="password"
name="password"
onChange={handleChange}
value={formData.password}
placeholder="Пароль"
id="authPassword"
/>
</div>
</div>
</div>
<span className="error">{modalError ? error : ""}</span>
<div className="button-box">
<BaseButton
onClick={async (e) => {
e.preventDefault();
submitHandler(e);
}}
styles="button-box__submit"
>
{isLoading ? <Loader /> : "Войти"}
</BaseButton>
</div>
</div>
<span onClick={() => closeModal()} className="exit"></span>
</ModalLayout>
);
};
export default ModalAuth;

View File

@ -0,0 +1,136 @@
.auth {
background: white;
padding: 40px 20px 40px 20px;
border: 1px solid #dde2e4;
border-radius: 8px;
width: 70%;
max-width: 900px;
font-family: "LabGrotesque", sans-serif;
&-body {
&__main {
width: 80%;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 20px;
&-title {
font-weight: 500;
font-size: 35px;
line-height: 32px;
display: flex;
justify-content: center;
margin: 0;
@media (max-width: 960px) {
font-size: 25px;
}
@media (max-width: 703px) {
align-items: center;
font-size: 20px;
}
span {
color: #52b709;
margin-left: 10px;
@media (max-width: 703px) {
margin-left: 5px;
}
}
}
.input-body {
margin-top: 44px;
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
@media (max-width: 703px) {
flex-direction: column;
align-items: center;
margin-top: 10px;
}
&__box {
display: flex;
flex-direction: column;
width: 47%;
@media (max-width: 703px) {
width: 85%;
}
h5 {
font-weight: 400;
font-size: 15px;
line-height: 18px;
margin: 0 0 10px 10px;
}
input {
height: 43px;
background: #eff2f7;
border-radius: 8px;
border: none;
margin-bottom: 5px;
font-size: 15px;
font-weight: 400;
line-height: 18px;
font-style: normal;
letter-spacing: normal;
text-align: left;
padding: 16px 15px 16px 22px;
outline: none;
}
.input-container {
margin: 0 0 20px 0;
width: 100%;
display: flex;
flex-direction: column;
}
}
}
.error {
color: red;
font-size: 11px;
font-weight: 400;
}
.button-box {
display: flex;
flex-direction: row;
margin-top: 10px;
&__submit {
width: 174px;
height: 50px;
font-size: 18px;
}
.disable {
opacity: 0.5;
pointer-events: none;
}
h5 {
display: flex;
align-items: flex-end;
font-size: 16px;
line-height: 28px;
p {
color: #406128;
text-decoration: underline;
margin: 0 0 0 5px;
}
}
}
}
}
}

View File

@ -7,6 +7,7 @@
border: 1px solid #dde2e4;
border-radius: 8px;
width: 60%;
font-family: "LabGrotesque", sans-serif;
@media (max-width: 1375px) {
width: 80%;
@ -110,7 +111,14 @@
border-radius: 8px;
border: none;
margin-bottom: 5px;
padding-left: 20px;
font-size: 15px;
font-weight: 400;
line-height: 18px;
font-style: normal;
letter-spacing: normal;
text-align: left;
padding: 16px 15px 16px 22px;
outline: none;
}
.input-container {

View File

@ -122,15 +122,6 @@ export const ModalTiсket = ({
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 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) {
apiRequest("/task/update-task", {
method: "PUT",
@ -380,82 +382,111 @@ export const ModalTiсket = ({
}
useEffect(() => {
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) => {
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
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();
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);
});
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
updateTimerSec = timerSeconds % 60;
if (!time.stopped_at) {
setTimerStart(true);
startTimer();
setTimerInfo(time);
}
});
}
);
}
return acc;
}, []);
setComments(comments);
});
apiRequest(`/file/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)) {
setTaskFiles(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 (
localStorage.getItem("role_status") !== "18" &&
Boolean(
if (!time.stopped_at) {
setTimerStart(true);
startTimer();
setTimerInfo(time);
}
});
} else {
setCurrentTimerCount({
hours: 0,
minute: 0,
seconds: 0
});
}
});
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
(res) => {
if (Array.isArray(res)) {
setTaskFiles(res);
} else {
setTaskFiles([]);
}
}
);
if (
localStorage.getItem("role_status") !== "18" &&
Array.isArray(correctProjectUsers) &&
!correctProjectUsers.find(
(item) => item.user_id === profileInfo.id_user
)
)
) {
setCorrectProjectUsers((prevState) => [
...prevState,
{
user: {
avatar: profileInfo.photo,
fio: profileInfo.fio
},
user_id: profileInfo.id_user
}
]);
) {
setCorrectProjectUsers((prevState) => [
...prevState,
{
user: {
avatar: profileInfo.photo,
fio: profileInfo.fio
},
user_id: profileInfo.id_user
}
]);
}
}
}, []);
}, [active]);
useEffect(() => {
let tagIds = taskTags.map((tag) => tag.id);
setCorrectProjectTags(
projectMarks.reduce((acc, cur) => {
if (!tagIds.includes(cur.id)) acc.push(cur);
return acc;
}, [])
);
if (Array.isArray(taskTags)) {
const tagIds = taskTags.map((tag) => tag.id);
setCorrectProjectTags(
projectMarks.reduce((acc, cur) => {
if (!tagIds.includes(cur.id)) acc.push(cur);
return acc;
}, [])
);
}
}, [taskTags]);
async function handleUpload(event) {
@ -534,13 +565,15 @@ export const ModalTiсket = ({
}
useEffect(() => {
let ids = members.map((user) => user.user_id);
setUsers(
projectUsers.reduce((acc, cur) => {
if (!ids.includes(cur.user_id)) acc.push(cur);
return acc;
}, [])
);
if (Array.isArray(members)) {
const ids = members.map((user) => user.user_id);
setUsers(
projectUsers.reduce((acc, cur) => {
if (!ids.includes(cur.user_id)) acc.push(cur);
return acc;
}, [])
);
}
}, [members]);
function copyTicketLink() {
@ -684,6 +717,7 @@ export const ModalTiсket = ({
editor={ClassicEditor}
data={inputsValue.description}
config={{
toolbar: ["link"],
removePlugins: [
"CKFinderUploadAdapter",
"CKFinder",
@ -695,7 +729,10 @@ export const ModalTiсket = ({
"ImageUpload",
"MediaEmbed",
"BlockQuote"
]
],
link: {
addTargetToExternalLinks: true
}
}}
onChange={(event, editor) => {
const data = editor.getData();
@ -713,7 +750,7 @@ export const ModalTiсket = ({
)}
{/*<img src={taskImg} className="image-task"></img>*/}
</div>
{Boolean(taskFiles.length) && (
{Boolean(taskFiles?.length) && (
<div className="task__files">
{taskFiles.map((file) => {
return (
@ -873,7 +910,7 @@ export const ModalTiсket = ({
)}
</div>
)}
{Boolean(members.length) && (
{Boolean(members?.length) && (
<div className="members">
<h5>Участники:</h5>
<div className="members__list">
@ -1005,23 +1042,24 @@ export const ModalTiсket = ({
<div className="workers_box-tag">
<div className="tags">
<div className="tags__selected">
{taskTags.map((tag) => {
return (
<div
className="tags__selected__item"
key={tag.id}
style={{ background: tag.color }}
>
<p>{tag.slug}</p>
<img
src={crossWhite}
className="delete"
alt="delete"
onClick={() => deleteTagFromTask(tag.id)}
/>
</div>
);
})}
{Array.isArray(taskTags) &&
taskTags.map((tag) => {
return (
<div
className="tags__selected__item"
key={tag.id}
style={{ background: tag.color }}
>
<p>{tag.slug}</p>
<img
src={crossWhite}
className="delete"
alt="delete"
onClick={() => deleteTagFromTask(tag.id)}
/>
</div>
);
})}
</div>
<div
className="tags__select"

View File

@ -30,10 +30,6 @@
max-height: 700px;
max-width: 915px;
@media (max-width: 990px) {
width: 96%;
}
@media (max-width: 880px) {
max-height: none;
overflow-y: inherit;
@ -590,10 +586,6 @@
width: 100%;
}
}
@media (max-width: 880px) {
width: 100%;
}
}
.members {
@ -613,6 +605,7 @@
position: relative;
border-left: 1px solid #f1f1f1;
width: 32%;
padding: 0 10px 10px 0;
.exit {
cursor: pointer;

View File

@ -331,6 +331,7 @@ export const TrackerModal = ({
status: 19
}
}).then((res) => {
console.log(res);
if (!Array.isArray(res.name)) {
const result = { ...res, columns: [] };
dispatch(setProject(result));
@ -625,7 +626,10 @@ export const TrackerModal = ({
"numberedList"
],
removePlugins: ["BlockQuote"],
placeholder: "Описание задачи"
placeholder: "Описание задачи",
link: {
addTargetToExternalLinks: true
}
}}
onChange={(event, editor) => {
const data = editor.getData();

View File

@ -31,6 +31,12 @@
align-items: center;
flex-direction: column;
padding-bottom: 15px;
width: 100%;
min-width: 700px;
@media (max-width: 770px) {
min-width: auto;
}
.select-priority {
background-color: white;
@ -338,8 +344,10 @@
}
.create-task-body {
width: 100%;
padding: 15px 30px;
display: flex;
display: grid;
grid-template-columns: 55% 45%;
column-gap: 20px;
&__left {
@ -356,7 +364,7 @@
.input-container {
background: #f1f1f1;
margin: 0 0 17px;
width: 393px;
width: 100%;
height: 47px;
input {
@ -407,10 +415,11 @@
display: flex;
flex-direction: column;
position: relative;
width: 100%;
.tags {
&__selected {
width: 250px;
width: 100%;
font-weight: 300;
line-height: 18px;
font-size: 15px;
@ -538,10 +547,10 @@
.select__priority {
position: relative;
width: 100%;
&__name {
color: #000;
width: 250px;
height: 47px;
font-size: 15px;
font-weight: 400;
@ -589,7 +598,7 @@
.select__executor {
background: #f1f1f1;
width: 250px;
width: 100%;
height: 47px;
font-weight: 300;
line-height: 18px;

View File

@ -223,7 +223,7 @@ export const ProfileCalendarComponent = React.memo(
</div>
<div className="calendar-component__body">
<div>
<div className="calendar-component__body__week-days">
<p>Понедельник</p>
<p>Вторник</p>
<p>Среда</p>
@ -232,6 +232,15 @@ export const ProfileCalendarComponent = React.memo(
<p>Суббота</p>
<p>Воскресенье</p>
</div>
<div className="calendar-component__body__week-days-mobile">
<p>ПН</p>
<p>ВТ</p>
<p>СР</p>
<p>ЧТ</p>
<p>ПТ</p>
<p>СБ</p>
<p>ВС</p>
</div>
<div className="calendar-component__form">
{calendar.map((week) =>

View File

@ -19,8 +19,17 @@
.summary__info {
padding-right: 25px;
@media (max-width: 500px) {
padding-right: 5px;
@media (max-width: 760px) {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
row-gap: 25px;
padding: 25px;
}
.summary__person {
margin: 0 10px 0 0;
}
.summary__skill {
@ -32,6 +41,12 @@
align-items: center;
column-gap: 10px;
p {
@media (max-width: 425px) {
display: none;
}
}
div {
font-size: 12px;
font-weight: 400;

View File

@ -63,8 +63,8 @@ export const ProjectTicket = ({ project, index }) => {
dispatch(deleteProject(project));
showNotification({
show: true,
text: "Проект успешно был перемещен в архив",
type: "archive"
text: "Проект успешно удален",
type: "success"
});
});
}

View File

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

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { forwardRef, useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { movePositionProjectTask } from "@redux/projectsTrackerSlice";
@ -14,173 +14,183 @@ import avatarMok from "assets/images/avatarMok.webp";
import "./trackerCardTask.scss";
const TrackerCardTask = ({
task,
projectBoard,
titleColor,
column,
openTicket,
startWrapperIndexTest,
setWrapperHover
}) => {
const dispatch = useDispatch();
const [taskHover, setTaskHover] = useState({});
const TrackerCardTask = forwardRef(
(
{
task,
projectBoard,
titleColor,
column,
openTicket,
startWrapperIndexTest,
setWrapperHover
},
ref
) => {
const dispatch = useDispatch();
const [taskHover, setTaskHover] = useState({});
const priority = {
2: "Высокий",
1: "Средний",
0: "Низкий"
};
const priority = {
2: "Высокий",
1: "Средний",
0: "Низкий"
};
const priorityClass = {
2: "high",
1: "middle",
0: "low"
};
const priorityClass = {
2: "high",
1: "middle",
0: "low"
};
function dragDropTaskHandler(e, task, column) {
e.preventDefault();
if (task.id === startWrapperIndexTest.current.task.id) {
return;
function dragDropTaskHandler(e, task, column) {
e.preventDefault();
if (task.id === startWrapperIndexTest.current.task.id) {
return;
}
const finishTask = column.tasks.indexOf(task);
dispatch(
movePositionProjectTask({
startTask: startWrapperIndexTest.current.task,
finishTask: task,
finishIndex: finishTask
})
);
}
const finishTask = column.tasks.indexOf(task);
function dragOverTaskHandler(e, task) {
e.preventDefault();
if (startWrapperIndexTest.current.task.id === task.id) {
return;
}
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
}
dispatch(
movePositionProjectTask({
startTask: startWrapperIndexTest.current.task,
finishTask: task,
finishIndex: finishTask
})
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
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>
</div>
<TrackerSelectColumn
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
currentColumn={column}
task={task}
/>
</>
);
}
);
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>
);
};
TrackerCardTask.displayName = "TrackerCardTask";
export default TrackerCardTask;

View File

@ -30,6 +30,10 @@
overflow: auto;
padding: 5px;
@media (max-width: 900px) {
row-gap: 0;
}
&::-webkit-scrollbar {
width: 3px;
border-radius: 10px;
@ -61,7 +65,7 @@
position: relative;
box-shadow: 0px 3px 2px -2px rgba(0, 0, 0, 0.06),
0px 5px 3px -2px rgba(0, 0, 0, 0.02);
border-radius: 6px;
border-radius: 6px 6px 0 0;
background: #ffffff;
cursor: pointer;
display: flex;
@ -76,6 +80,7 @@
@media (max-width: 900px) {
width: 100%;
padding: 6px 10px 5px 10px;
max-height: none;
&:hover {

View File

@ -2,15 +2,16 @@
display: none;
@media (max-width: 900px) {
background: #ffffff;
display: flex;
width: 100%;
margin: 10px 0;
margin: 0 0 15px 0;
justify-content: space-between;
align-items: center;
padding: 2px 6px;
padding: 0 6px;
cursor: pointer;
border: 1px solid #e3e2e2;
border-radius: 8px;
border-top: 1px solid #e3e2e2;
border-radius: 0 0 6px 6px;
position: relative;
p {

View File

@ -121,6 +121,7 @@ export const TrackerTaskComment = ({
editor={ClassicEditor}
data={commentsEditText}
config={{
toolbar: ["link"],
removePlugins: [
"CKFinderUploadAdapter",
"CKFinder",
@ -132,7 +133,10 @@ export const TrackerTaskComment = ({
"ImageUpload",
"MediaEmbed",
"BlockQuote"
]
],
link: {
addTargetToExternalLinks: true
}
}}
onChange={(event, editor) => {
const data = editor.getData();

View File

@ -90,7 +90,11 @@ export const FormPage = () => {
Заявка на собеседование через телеграм
</div>
<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} />
</a>
</div>

View File

@ -5,6 +5,7 @@ import { Link, NavLink } from "react-router-dom";
import { BurgerButton } from "@components/BurgerMenu/burgerButton";
import { BurgerMenu } from "@components/BurgerMenu/burgerMenu";
import { Footer } from "@components/Common/Footer/Footer";
import ModalAuth from "@components/Modal/ModalAuth/ModalAuth";
import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration";
import arrow from "assets/icons/arrows/arrowLanding.svg";
@ -13,11 +14,16 @@ import clue from "assets/icons/landingClue.svg";
import tracker from "assets/icons/landingTracker.svg";
import codeBg from "assets/images/landing/backgroundCode.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";
export const Landing = () => {
const [modalReg, setModalReg] = useState(false);
const [modalAuth, setModalAuth] = useState(false);
const [menuActive, setMenuActive] = useState(false);
const opportunities = [
@ -29,22 +35,22 @@ export const Landing = () => {
{
name: "<span>Найти</span> работу <br/> в IT",
path: "/stack",
img: cat
img: searchIT
},
{
name: "<span>Система</span> контроля версий GIT",
path: "/stack",
img: cat
img: systemControlGit
},
{
name: "<span>Управление</span> задачами",
path: "/landing-tracker",
img: cat
img: taskManagement
},
{
name: "<span>Система</span> для отчётности",
path: "/stack",
img: cat
img: reportingSystem
},
{
name: "Все наши предложения",
@ -57,14 +63,20 @@ export const Landing = () => {
return (
<section className="landing">
<ModalRegistration active={modalReg} setActive={setModalReg} />
<ModalAuth active={modalAuth} setActive={setModalAuth} />
<BurgerMenu active={menuActive} />
<div className="landing__container">
<div className="landing__head">
<h2 className="head__logo">ITGUILD</h2>
<Link className="head__signIn" to="/auth">
<div
className="head__signIn"
onClick={(e) => {
e.preventDefault();
setModalAuth(true);
}}
>
войти в систему
</Link>
</div>
<div
className="head__signUp"
onClick={(e) => {

View File

@ -59,6 +59,7 @@
font-weight: 400;
border-radius: 32px;
z-index: 1;
cursor: pointer;
@media (max-width: 431px) {
display: none;

View File

@ -1,6 +1,7 @@
import React from "react";
import { Link, NavLink } from "react-router-dom";
import { AuthHeader } from "@components/Common/AuthHeader/AuthHeader";
import { Footer } from "@components/Common/Footer/Footer";
import arrow from "assets/icons/arrows/arrowLanding.svg";
@ -12,6 +13,11 @@ import ellipseGreen from "assets/images/landingTracker/ellipseGreen.svg";
import cat from "assets/images/landingTracker/landingCat.webp";
import flag from "assets/images/landingTracker/projectsFlag.webp";
import questionMark from "assets/images/landingTracker/questionMark.svg";
import reportingSystem from "assets/images/landingTracker/reportingSystem.webp";
import searchIT from "assets/images/landingTracker/searchIT.webp";
import systemControlGit from "assets/images/landingTracker/systemControlGit.webp";
import target from "assets/images/landingTracker/target.webp";
import taskManagement from "assets/images/landingTracker/taskManagement.webp";
import trackerCup from "assets/images/landingTracker/trackerCup.webp";
import trackerPreview from "assets/images/landingTracker/trackerPreview.webp";
import trackerSign from "assets/images/landingTracker/trackerSign.webp";
@ -21,20 +27,20 @@ import "./LandingTracker.scss";
export const LandingTracker = () => {
const goals = [
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>уточнение</span> деталей и <span>обсуждение</span> условий с менеджером ITGUILD"
miniInfo: "Простота использования",
info: "<span>интуитивно понятный интерфейс</span> делает работу с нашим сервисом легкой и приятной"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>подписание договора</span> без обязательств оплаты на данном этапе"
miniInfo: "Гибкость и адаптивность",
info: "мы предлогаем <span>инструменты, которые подойдут</span> именно вашему проекту"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>формирование</span> команды или подбор отдельных специалистов под требования клиентов"
miniInfo: "Совместная работа без границ",
info: "сотрудничайте, общайтесь и делитесь ресурсами <span>в реальном времени, в любой точке мира</span>"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>интеграция специалистов</span> в команду клиента, ежедневная отчетность под контролем менеджера ITGUILD"
miniInfo: "Безопасность и надежность",
info: "постоянный мониторинг системы <span>позволяет обеспечивать безопасность</span> ваших данных"
}
];
@ -47,22 +53,22 @@ export const LandingTracker = () => {
{
name: "<span>Найти</span> работу <br/> в IT",
path: "/stack",
img: cat
img: searchIT
},
{
name: "<span>Система</span> контроля <br/> версий GIT",
path: "/stack",
img: cat
img: systemControlGit
},
{
name: "<span>Управление</span> <br/> задачами",
path: "/landing-tracker",
img: cat
img: taskManagement
},
{
name: "<span>Система</span> для <br/> отчётности",
path: "/stack",
img: cat
img: reportingSystem
},
{
name: "Все наши <br/> предложения",
@ -74,6 +80,7 @@ export const LandingTracker = () => {
return (
<section className="tracker">
<AuthHeader />
<section className="tracker__intro">
<img className="intro__question-mark" src={questionMark} alt="" />
<img className="intro__code" src={code} alt="" />
@ -120,7 +127,7 @@ export const LandingTracker = () => {
<Link to="/auth">войти</Link>
</button>
<button className="signUp">
<Link to="/auth">регистрация</Link>
<Link to="/auth">авторизация</Link>
</button>
</div>
<div className="presentation__tracker-preview">
@ -173,9 +180,9 @@ export const LandingTracker = () => {
);
})}
</div>
{/* <div className="steps__portfolio">
<img src={portfolio} alt="portfolio" />
</div> */}
<div className="goals__target">
<img src={target} alt="target" />
</div>
</div>
</section>
@ -195,7 +202,7 @@ export const LandingTracker = () => {
<Link to="/auth">войти</Link>
</button>
<button className="signUp">
<Link to="/auth">регистрация</Link>
<Link to="/auth">авторизация</Link>
</button>
</div>
</div>
@ -205,6 +212,14 @@ export const LandingTracker = () => {
</h3>
<img className="invite__logo__sign" src={trackerSign} alt="" />
<img className="invite__logo__ellipse" src={ellipseGreen} alt="" />
<div className="invite-auth__buttons">
<button className="signUp-modile">
<Link to="/auth">авторизация</Link>
</button>
<button className="signIn-modile">
<Link to="/auth">войти</Link>
</button>
</div>
</div>
</div>
</section>

View File

@ -1,6 +1,31 @@
.tracker {
font-family: "GT Eesti Pro Display";
// section:not(:nth-child(2)):not(:nth-child(3)):not(:nth-child(4)):not(
// :nth-child(5)
// ):not(:nth-child(6)) {
// display: none;
// }
.auth-header {
display: none;
@media (max-width: 431px) {
display: flex;
background-color: #a7ca60;
}
.burger__line {
background-color: #4a4a4a;
}
.auth__buttons {
.signIn {
background-color: #eeeeee;
}
}
}
&__container {
margin: 0 auto;
// padding: 85px 0 90px;
@ -12,22 +37,39 @@
background-color: #a7ca60;
position: relative;
@media (max-width: 431px) {
height: 485px;
overflow: hidden;
}
.intro {
&__question-mark {
position: absolute;
right: 15%;
@media (max-width: 431px) {
display: none;
}
}
&__code {
position: absolute;
mix-blend-mode: plus-lighter;
bottom: 96px;
left: 16%;
@media (max-width: 431px) {
display: none;
}
}
&__code--top {
position: absolute;
mix-blend-mode: plus-lighter;
top: 20px;
left: 38%;
@media (max-width: 431px) {
display: none;
}
}
&__container {
@ -37,6 +79,9 @@
overflow: hidden;
@media (max-width: 431px) {
flex-direction: column-reverse;
align-items: center;
height: auto;
}
}
@ -51,6 +96,10 @@
font-size: 343px;
font-weight: 400;
line-height: 325.92px;
@media (max-width: 431px) {
display: none;
}
}
&__cup {
@ -58,6 +107,17 @@
bottom: -85px;
right: -150px;
@media (max-width: 431px) {
position: static;
margin: -90px 0 0 0;
}
img {
@media (max-width: 431px) {
height: 350px;
}
}
&::before {
content: "Не нужно заваривать мышь";
display: flex;
@ -82,6 +142,12 @@
line-height: 19.72px;
letter-spacing: 0.01em;
text-align: center;
@media (max-width: 431px) {
width: 125px;
height: 106px;
left: 170px;
}
}
}
}
@ -92,9 +158,17 @@
color: #607536;
max-width: 455px;
@media (max-width: 431px) {
margin: 0 20px;
}
&__sublogo {
margin-top: 37px;
@media (max-width: 431px) {
display: none;
}
h5 {
font-size: 29px;
font-weight: 900;
@ -122,6 +196,13 @@
line-height: 37.29px;
letter-spacing: 0.01em;
margin: 101px 0 34px 0;
@media (max-width: 431px) {
font-size: 29px;
line-height: 32.77px;
text-align: center;
margin: 21px 0 26px 0;
}
}
p {
@ -129,6 +210,12 @@
font-weight: 500;
line-height: 37.29px;
letter-spacing: 0.01em;
@media (max-width: 431px) {
font-size: 25px;
line-height: 28.25px;
text-align: center;
}
}
}
}
@ -144,12 +231,20 @@
mix-blend-mode: plus-lighter;
bottom: 225px;
right: 18%;
@media (max-width: 431px) {
display: none;
}
}
&__code--top {
position: absolute;
mix-blend-mode: plus-lighter;
top: 60px;
left: 25%;
@media (max-width: 431px) {
display: none;
}
}
&__ellipse {
position: absolute;
@ -158,6 +253,10 @@
top: -90px;
left: 50%;
transform: translate(-50%);
@media (max-width: 431px) {
display: none;
}
}
&__container {
@ -170,6 +269,7 @@
z-index: 2;
@media (max-width: 431px) {
height: 660px;
}
h5 {
@ -178,6 +278,13 @@
font-weight: 700;
line-height: 38.28px;
margin-top: 95px;
@media (max-width: 431px) {
font-size: 19px;
line-height: 22.04px;
text-align: center;
margin-top: 37px;
}
}
h4 {
@ -187,6 +294,13 @@
font-weight: 900;
line-height: 119.48px;
margin-top: 9px;
@media (max-width: 431px) {
font-size: 50px;
font-weight: 900;
line-height: 58px;
text-align: center;
}
}
p {
@ -198,6 +312,13 @@
max-width: 609px;
margin-bottom: 52px;
@media (max-width: 431px) {
font-size: 15px;
line-height: 17.4px;
text-align: center;
max-width: 370px;
}
span {
font-weight: 700;
}
@ -208,6 +329,10 @@
display: flex;
column-gap: 29px;
@media (max-width: 431px) {
column-gap: 12px;
}
button {
width: 185px;
height: 45px;
@ -238,6 +363,13 @@
margin-top: 61px;
position: relative;
@media (max-width: 431px) {
margin-top: 37px;
overflow: hidden;
height: 315px;
left: 150px;
}
.tracker-preview {
&__buttons {
display: flex;
@ -278,12 +410,24 @@
left: 21%;
z-index: 2;
@media (max-width: 431px) {
width: 255px;
height: 102px;
left: -22.26px;
border-radius: 24px 0px 44px 0px;
padding: 25px 0 0 60px;
}
span {
font-size: 26px;
font-weight: 900;
line-height: 28.34px;
letter-spacing: 0.03em;
text-align: left;
@media (max-width: 431px) {
max-width: 174px;
}
}
p {
@ -291,6 +435,10 @@
font-weight: 300;
line-height: 19.65px;
text-align: left;
@media (max-width: 431px) {
display: none;
}
}
}
}
@ -307,6 +455,10 @@
bottom: -96px;
left: 7%;
z-index: 1;
@media (max-width: 431px) {
display: none;
}
}
&__container {
@ -315,6 +467,11 @@
height: 720px;
text-align: center;
align-items: center;
@media (max-width: 431px) {
height: 1020px;
overflow: hidden;
}
}
&-head {
@ -333,6 +490,13 @@
filter: drop-shadow(7px 0px 10px rgba(0, 0, 0, 0.1294117647));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
@media (max-width: 431px) {
font-size: 110px;
line-height: 110px;
letter-spacing: 0.01em;
margin-top: 20px;
}
}
&__info {
@ -345,6 +509,11 @@
letter-spacing: 0.02em;
color: #eeeeee;
@media (max-width: 431px) {
bottom: -55px;
max-width: 372px;
}
span {
font-weight: 700;
}
@ -358,9 +527,10 @@
column-gap: 48px;
@media (max-width: 431px) {
flex-direction: column;
display: grid;
grid-template-columns: 1fr 1fr;
row-gap: 86px;
margin-top: 65px;
margin-top: 95px;
}
.item {
@ -369,9 +539,17 @@
&:nth-child(2) {
margin-right: 41px;
@media (max-width: 431px) {
margin: 0;
}
}
&:nth-child(3) {
margin-left: 41px;
@media (max-width: 431px) {
margin: 0;
}
}
}
@ -397,8 +575,9 @@
letter-spacing: 0.01em;
@media (max-width: 431px) {
font-size: 14px;
max-width: 124px;
font-size: 12px;
font-weight: 700;
max-width: 107px;
text-align: left;
}
}
@ -424,8 +603,8 @@
border-radius: 8px;
@media (max-width: 431px) {
width: 324px;
height: 153px;
width: 200px;
height: 205px;
}
.item {
@ -446,6 +625,11 @@
}
}
}
&__target {
position: absolute;
bottom: 0;
}
}
}
@ -466,15 +650,33 @@
height: 582px;
overflow: hidden;
column-gap: 133px;
@media (max-width: 431px) {
height: auto;
padding-top: 35px;
display: flex;
flex-direction: column;
}
}
&__info {
max-width: 541px;
@media (max-width: 431px) {
max-width: 377px;
margin: 0 auto;
}
h5 {
color: #607536;
font-size: 44px;
font-weight: 700;
line-height: 51.04px;
@media (max-width: 431px) {
font-size: 29px;
line-height: 33.64px;
}
}
p {
@ -484,6 +686,10 @@
font-weight: 300;
line-height: 19.72px;
@media (max-width: 431px) {
margin: 30px 0 22px 0;
}
span {
font-weight: 700;
}
@ -494,6 +700,11 @@
display: flex;
column-gap: 29px;
@media (max-width: 431px) {
flex-direction: column;
row-gap: 22px;
}
button {
width: 185px;
height: 45px;
@ -509,6 +720,18 @@
}
background-color: #ffffff;
border: none;
@media (max-width: 431px) {
display: none;
}
&-modile {
a {
color: #607536;
}
background-color: #ffffff;
border: none;
}
}
.signUp {
@ -517,6 +740,18 @@
}
border: 1px solid #ffffff;
background: none;
@media (max-width: 431px) {
display: none;
}
&-modile {
a {
color: #ffffff;
}
border: 1px solid #ffffff;
background: none;
}
}
}
@ -526,6 +761,12 @@
position: relative;
align-items: center;
@media (max-width: 431px) {
flex-direction: row;
padding-left: 18px;
column-gap: 18px;
}
h3 {
color: #ffffff;
font-family: "Geraspoheko";
@ -534,6 +775,13 @@
line-height: 325.92px;
z-index: 3;
position: relative;
@media (max-width: 431px) {
font-size: 140px;
font-weight: 400;
line-height: 140px;
z-index: 2;
}
}
&__sign {
@ -541,6 +789,12 @@
z-index: 2;
left: -180px;
top: 70px;
@media (max-width: 431px) {
width: 90px;
left: -40px;
top: 50px;
}
}
&__ellipse {
@ -548,6 +802,11 @@
width: 463px;
height: 563px;
z-index: 1;
@media (max-width: 431px) {
width: 220px;
height: 220px;
}
}
}
}
@ -571,6 +830,10 @@
display: flex;
flex-direction: column;
align-items: center;
@media (max-width: 431px) {
height: 1170px;
}
}
&__project {
@ -582,6 +845,15 @@
border-radius: 8px;
border: 1px solid #f8f8f8;
@media (max-width: 431px) {
align-items: normal;
flex-direction: column;
row-gap: 32px;
height: 266px;
max-width: 397px;
padding: 32px 30px;
}
.project__img {
border-radius: 8px;
width: 99px;
@ -620,6 +892,11 @@
letter-spacing: 0.03em;
text-align: center;
margin: 42px 0 77px 0;
@media (max-width: 431px) {
font-size: 19px;
line-height: 22.04px;
}
}
&__opportunities {
@ -649,6 +926,8 @@
@media (max-width: 431px) {
padding: 0;
width: 40%;
height: auto;
display: block;
div {
display: flex;
@ -663,6 +942,7 @@
border: 0.5px solid #ffffff;
border-radius: 18px;
padding: 10px;
height: 221px;
}
}

View File

@ -92,13 +92,13 @@ export const PartnerEmployeeReport = () => {
<>
<div className="employee-report__info">
<div className="employee-report__name">
<h2>{userInfo.fio}</h2>
<p>{userInfo.position}</p>
<h2>{userInfo?.userCard.fio}</h2>
<p>{userInfo?.userCard.position.name}</p>
</div>
<div className="employee-report__skills">
{userInfo?.stack &&
userInfo.stack.map((skill, index) => {
return <span key={index}>{skill}</span>;
{userInfo?.userCard?.skillValues &&
userInfo?.userCard?.skillValues.map((skill) => {
return <span key={skill.id}>{skill.skill.name}</span>;
})}
</div>
</div>

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { apiRequest } from "@api/request";
@ -11,6 +11,7 @@ import { Navigation } from "@components/Navigation/Navigation";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import tgSettingsIcon from "assets/icons/tgSettingsIcon.svg";
import astral from "assets/images/logo/astralLogo.png";
import kontur from "assets/images/logo/konturLogo.png";
@ -18,6 +19,7 @@ import "./partnerSettings.scss";
export const PartnerSettings = () => {
const { showNotification } = useNotification();
const [tgToken, setTgToken] = useState();
const [inputsValue, setInputsValue] = useState({
name: "",
oldPassword: "",
@ -30,6 +32,15 @@ export const PartnerSettings = () => {
});
const [loader, setLoader] = useState(false);
const [tgLoader, setTgLoader] = useState(false);
useEffect(() => {
apiRequest("/user-tg-bot/get-token", {
method: "GET"
}).then((data) => {
setTgToken(data.token);
});
}, []);
const setSettings = () => {
if (inputsValue.name.length < 2) {
@ -80,6 +91,24 @@ export const PartnerSettings = () => {
});
});
};
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(tgToken);
showNotification({
show: true,
text: "Телеграм токен успешно скопирован",
type: "success"
});
} catch (err) {
showNotification({
show: true,
text: "Ошибка копирования",
type: "error"
});
}
};
return (
<div className="settings">
<ProfileHeader />
@ -183,6 +212,34 @@ export const PartnerSettings = () => {
использования персональных данных
</span>
</div>
<div className="partner-settings__report">
<h3 className="settings__title">Телеграмм бот</h3>
<p className="settings__label">Тelegram токен</p>
<div className="settings__input">
<span>{tgToken}</span>
</div>
<div className="settings__buttons">
{tgLoader ? (
<Loader style={"green"} width={"40px"} height={"40px"} />
) : (
<BaseButton
onClick={handleCopy}
styles={"settings__buttons-save"}
>
Скопировать
</BaseButton>
)}
</div>
<div className="settings__agreement-tg">
<a href="#" target="_blank" rel="noopener noreferrer">
<img src={tgSettingsIcon} alt="" />
</a>
Ссылка на телеграм бот с инструкцией
</div>
</div>
{/* <div className="partner-settings__report">
<h3 className="settings__title">Документы и отчеты</h3>
<p className="settings__label">Изменить провадера ЭДО</p>

View File

@ -29,13 +29,14 @@
font-size: 15px;
line-height: 18px;
color: #000000;
margin: 15px 0 10px 0;
margin: 30px 0 10px 0;
}
&__input {
display: flex;
flex-direction: column;
row-gap: 5px;
input {
padding: 5px 10px;
background: #eff2f7;
@ -46,6 +47,16 @@
outline: none;
}
span {
padding: 5px 10px;
background: #eff2f7;
border-radius: 8px;
height: 35px;
border: none;
font-size: 15px;
outline: none;
}
.error {
color: red;
font-size: 12px;
@ -65,6 +76,18 @@
line-height: 18px;
color: #000000;
font-weight: 300;
&-tg {
font-size: 15px;
font-weight: 400;
line-height: 18px;
img {
width: 40px;
height: 40px;
margin-right: 20px;
}
}
}
&__buttons {
@ -140,6 +163,8 @@
display: flex;
flex-direction: row;
margin-top: 50px;
column-gap: 40px;
justify-content: center;
}
&__report,

View File

@ -65,23 +65,25 @@ export const PartnerCategories = () => {
{
label: "",
renderCell: (item) => (
<img
className="table__avatar"
src={urlForLocal(item?.employee.avatar)}
alt="avatar"
/>
<Link to={`/profile/summary/${item.user_id}`}>
<img
className="table__avatar"
src={urlForLocal(item?.employee.avatar)}
alt="avatar"
/>
</Link>
)
},
{
label: "Данные",
renderCell: (item) => (
<div className="table__info">
<Link className="table__info" to={`/profile/summary/${item.user_id}`}>
<p>{item?.employee.fio}</p>
<span>
{LEVELS[item?.resume.userCard.level]} /{" "}
{SKILLS[item?.resume.userCard.position_id]}
</span>
</div>
</Link>
)
// sort: { sortKey: "NAME" }
},

View File

@ -1,7 +1,7 @@
import moment from "moment";
import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom";
import { Link, useLocation, useParams } from "react-router-dom";
import {
activeLoader,
@ -51,6 +51,9 @@ import avatarMok from "assets/images/avatarMok.webp";
export const ProjectTracker = () => {
const dispatch = useDispatch();
const projectId = useParams();
const taskParams = useParams();
const taskRefs = useRef([]);
const hasRunEffect = useRef(false);
const [openColumnSelect, setOpenColumnSelect] = useState({});
const [selectedTab, setSelectedTab] = useState(0);
@ -78,6 +81,19 @@ export const ProjectTracker = () => {
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(() => {
let columnsTasksEmpty = true;
if (Object.keys(projectBoard).length) {
@ -145,21 +161,32 @@ export const ProjectTracker = () => {
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);
setModalActiveTicket(true);
const currentUrl = window.location.pathname;
const newUrl = `${currentUrl}/task/${task.id}`;
window.history.pushState({}, "", newUrl);
updateUrlWithTaskId(task.id);
document.body.style.overflow = "hidden";
}
useEffect(() => {
const currentUrl = window.location.pathname;
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
window.history.replaceState({}, "", newUrl);
}, []);
function deleteColumn(column) {
const priorityColumns = [];
apiRequest("/project-column/update-column", {
@ -421,19 +448,16 @@ export const ProjectTracker = () => {
</Link>
</div>
</div>
{Boolean(modalActiveTicket) && (
<ModalTicket
active={modalActiveTicket}
setActive={setModalActiveTicket}
task={selectedTicket}
projectId={projectBoard.id}
projectName={projectBoard.name}
projectUsers={projectBoard.projectUsers}
projectOwnerId={projectBoard.owner_id}
projectMarks={projectBoard.mark}
/>
)}
<ModalTicket
active={modalActiveTicket}
setActive={setModalActiveTicket}
task={selectedTicket}
projectId={projectBoard.id}
projectName={projectBoard.name}
projectUsers={projectBoard.projectUsers}
projectOwnerId={projectBoard.owner_id}
projectMarks={projectBoard.mark}
/>
<div className="tasks__container">
{Boolean(projectBoard?.columns) &&
@ -535,6 +559,9 @@ export const ProjectTracker = () => {
startWrapperIndexTest={startWrapperIndexTest}
task={task}
titleColor={titleColor}
ref={(el) => {
taskRefs.current[task.id] = el;
}}
/>
);
})}

View File

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

View File

@ -43,6 +43,8 @@ const Statistics = () => {
});
}, []);
useEffect(() => {}, [projectInfo]);
const teams = [
{
avatar: mockAvatar,
@ -121,7 +123,7 @@ const Statistics = () => {
<img src={link} alt="#" />
<span
className="return-text"
onClick={() => copyProjectLink("62")}
onClick={() => copyProjectLink(projectInfo.id)}
>
ссылка на проект
</span>
@ -190,38 +192,36 @@ const Statistics = () => {
<div className="list-team__body">
{projectStatistic?.participants.map((person, index) => {
return (
<>
<div className="list-team__item" key={index}>
<div className="person-name">
<img
src={
person.avatar
? urlForLocal(person.avatar)
: mockAvatar
}
alt="avatar"
/>
<p>{person.username}</p>
</div>
<div className="person-email">
<img src={emailImg} alt="#" />
<p>{person.email}</p>
</div>
<p className="person-type">
{person.role ? person.role : "-"}
</p>
<span
className={
person.status
? "status status-active"
: "status status-none"
<div className="list-team__item" key={index}>
<div className="person-name">
<img
src={
person.avatar
? urlForLocal(person.avatar)
: mockAvatar
}
>
{person.status ? "Активно" : "Не активно"}
</span>
alt="avatar"
/>
<p>{person.username}</p>
</div>
</>
<div className="person-email">
<img src={emailImg} alt="#" />
<p>{person.email}</p>
</div>
<p className="person-type">
{person.role ? person.role : "-"}
</p>
<span
className={
person.status
? "status status-active"
: "status status-none"
}
>
{person.status ? "Активно" : "Не активно"}
</span>
</div>
);
})}
</div>

View File

@ -15,6 +15,7 @@
display: flex;
justify-content: space-between;
margin: 15px 0 0 0;
padding: 0 20px;
&__return {
img {
@ -106,6 +107,7 @@
border-radius: 12px;
background: #f1f1f1;
padding-left: 31px;
margin: 0 10px;
p {
color: #5b6871;

View File

@ -2,7 +2,7 @@ import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
import { CKEditor } from "@ckeditor/ckeditor5-react";
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";
import { useParams } from "react-router-dom";
import { getProfileInfo } from "@redux/outstaffingSlice";
@ -27,19 +27,18 @@ import avatarMok from "assets/images/avatarMok.webp";
import "./summary.scss";
export const Summary = () => {
if (localStorage.getItem("role_status") === "18") {
return <Navigate to="/profile" replace />;
}
const profileInfo = useSelector(getProfileInfo);
const [openGit, setOpenGit] = useState(false);
const [gitInfo, setGitInfo] = useState([]);
const [editSummaryOpen, setEditSummaryOpen] = useState(false);
const [editSkills, setEditSkills] = useState(false);
const [userInfo, setUserInfo] = useState({});
const [summary, setSummary] = useState("");
const [selectedSkills, setSelectedSkills] = useState([]);
const [selectSkillsOpen, setSelectSkillsOpen] = useState(false);
const [skillsList, seSkillsList] = useState([]);
const { showNotification } = useNotification();
const { id: userId } = useParams();
useEffect(() => {
apiRequest(
@ -48,8 +47,10 @@ export const Summary = () => {
}, []);
useEffect(() => {
setSummary(profileInfo.vc_text);
setSelectedSkills(profileInfo.skillValues);
if (!userId) {
setSummary(profileInfo.vc_text);
setSelectedSkills(profileInfo.skillValues);
}
}, [profileInfo]);
useEffect(() => {
@ -58,6 +59,41 @@ export const Summary = () => {
});
}, []);
useEffect(() => {
if (userId) {
apiRequest(`/resume?userId=${userId}`).then((res) => {
setUserInfo({
photo: res.userCard.photo,
fio: res.userCard.fio,
specification: res.userCard.specification,
level: res.userCard.level_title,
position: res.userCard.position.name
});
setSummary(res.userCard.vc_text);
setSelectedSkills(res.userCard.skillValues);
});
}
}, [userId]);
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() {
apiRequest("/resume/edit-skills", {
method: "PUT",
@ -66,7 +102,13 @@ export const Summary = () => {
skill: selectedSkills.map((item) => item.skill_id)
}
}
}).then(() => {});
}).then(() => {
showNotification({
show: true,
text: "Изменения успешно сохранены",
type: "success"
});
});
}
function editSummary() {
@ -108,7 +150,9 @@ export const Summary = () => {
<div className="summary__person">
<img
src={
profileInfo?.photo
userId
? urlForLocal(userInfo.photo)
: profileInfo?.photo
? urlForLocal(profileInfo.photo)
: avatarMok
}
@ -116,12 +160,18 @@ export const Summary = () => {
alt="avatar"
/>
<p className="summary__name">
{profileInfo?.fio || profileInfo?.username}{" "}
{profileInfo.specification}
{userId
? userInfo.fio
: profileInfo?.fio || profileInfo?.username}{" "}
{userId ? userInfo.specification : profileInfo.specification}
</p>
<hr />
<div className="summary__direction">Front End</div>
<div className="summary__level">Middle+</div>
<div className="summary__direction">
{userId ? userInfo.position : profileInfo?.position?.name}
</div>
<div className="summary__level">
{userId ? userInfo.level : profileInfo?.level_title}
</div>
</div>
{!openGit && (
<button className="summary__git" onClick={() => setOpenGit(true)}>
@ -134,17 +184,19 @@ export const Summary = () => {
<div className="summary__skills skills__section">
<div className="summary__sections__head">
<h3>Основной стек</h3>
<button
className={editSkills ? "edit" : ""}
onClick={() => {
if (editSkills) {
setSkills();
}
setEditSkills(!editSkills);
}}
>
{editSkills ? "Сохранить" : "Редактировать"}
</button>
{!userId && (
<button
className={editSkills ? "edit" : ""}
onClick={() => {
if (editSkills) {
setSkills();
}
setEditSkills(!editSkills);
}}
>
{editSkills ? "Сохранить" : "Редактировать"}
</button>
)}
</div>
<div className="skills__section__items">
{editSkills ? (
@ -157,13 +209,7 @@ export const Summary = () => {
<img
src={deleteIcon}
alt="deleteIcon"
onClick={() =>
setSelectedSkills((prevValue) =>
prevValue.filter(
(item) => item.skill_id !== skill.skill_id
)
)
}
onClick={() => deleteSkill(skill)}
/>
</span>
);
@ -184,12 +230,7 @@ export const Summary = () => {
{skillsList.map((skill) => {
return (
<p
onClick={() =>
setSelectedSkills((prevValue) => [
...prevValue,
{ skill: skill, skill_id: skill.id }
])
}
onClick={() => addSkill(skill)}
key={skill.id}
className="select-skills__item"
>
@ -205,7 +246,7 @@ export const Summary = () => {
<div className="skills__section__items__wrapper">
{selectedSkills &&
selectedSkills.map((skill, index) => (
<span key={skill.id} className="skill_item">
<span key={skill.skill_id} className="skill_item">
{skill.skill.name}
{selectedSkills.length > index + 1 && ","}
</span>
@ -225,17 +266,19 @@ export const Summary = () => {
<div className="experience__block">
<div className="summary__sections__head">
<h3>Опыт работы</h3>
<button
className={editSummaryOpen ? "edit" : ""}
onClick={() => {
if (editSummaryOpen) {
editSummary();
}
setEditSummaryOpen(!editSummaryOpen);
}}
>
{editSummaryOpen ? "Сохранить" : "Редактировать"}
</button>
{!userId && (
<button
className={editSummaryOpen ? "edit" : ""}
onClick={() => {
if (editSummaryOpen) {
editSummary();
}
setEditSummaryOpen(!editSummaryOpen);
}}
>
{editSummaryOpen ? "Сохранить" : "Редактировать"}
</button>
)}
</div>
{editSummaryOpen ? (
<CKEditor
@ -284,7 +327,7 @@ export const Summary = () => {
<a
href={itemGit.link}
target="_blank"
rel="noreferrer"
rel="noopener noreferrer"
key={itemGit.id}
className="summary__section-git-item git-item"
>
@ -305,7 +348,7 @@ export const Summary = () => {
className="git-item__link"
href={itemGit.link}
target="_blank"
rel="noreferrer"
rel="noopener noreferrer"
>
<img src={rightArrow} alt="arrowRight" />
</a>

View File

@ -1,6 +1,11 @@
import React from "react";
import { Route, Routes } from "react-router-dom";
import { Navigate, Route, Routes } from "react-router-dom";
import { Auth } from "@pages/Auth/Auth";
import { CompanyInfo } from "@pages/CompanyInfo/CompanyInfo";
import { Forms } from "@pages/Forms/Forms";
import { Landing } from "@pages/Landing/Landing";
import { LandingTracker } from "@pages/LandingTracker/LandingTracker";
import { OpenRequest } from "@pages/OpenRequests/OpenRequest";
import { PartnerSettings } from "@pages/PartnerSettings/PartnerSettings";
import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties";
@ -10,11 +15,14 @@ import { ProjectTracker } from "@pages/ProjectTracker/ProjectTracker";
import { PassingTests } from "@pages/Quiz/PassingTests";
import { QuizPage } from "@pages/Quiz/QuizPage";
import { QuizReportPage } from "@pages/Quiz/QuizReportPage";
import { Stack } from "@pages/Stack/Stack";
import Statistics from "@pages/Statistics/Statistics";
import { Summary } from "@pages/Summary/Summary";
import { Tracker } from "@pages/Tracker/Tracker";
import { TrackerIntro } from "@pages/TrackerIntro/TrackerIntro";
import { Vacancy } from "@pages/Vacancy/Vacancy";
import { ViewReport } from "@pages/ViewReport/ViewReport";
import { WelcomePage } from "@pages/WelcomePage/WelcomePage";
import TicketFullScreen from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
import { ProfileCalendar } from "@components/ProfileCalendar/ProfileCalendar";
@ -23,6 +31,16 @@ import { ReportForm } from "@components/ReportForm/ReportForm";
export const DeveloperPage = () => {
return (
<Routes>
<Route exact path="/auth" element={<Auth />} />
<Route exact path="/welcome-page" element={<WelcomePage />} />
<Route exact path="/stack" element={<Stack />} />
<Route exact path="/landing-tracker" element={<LandingTracker />} />
<Route exact path="/" element={<Landing />} />
<Route path="*" element={<Navigate to="/auth" replace />} />
<Route exact path="/tracker-intro" element={<TrackerIntro />} />
<Route exact path="/forms" element={<Forms />} />
<Route exact path="/company" element={<CompanyInfo />} />
<Route exact path="/tracker/task/:id" element={<TicketFullScreen />} />
<Route
exact

View File

@ -1,8 +1,13 @@
import React from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import { Auth } from "@pages/Auth/Auth";
import { CompanyInfo } from "@pages/CompanyInfo/CompanyInfo";
import { FormPage } from "@pages/FormPage/FormPage";
import { Forms } from "@pages/Forms/Forms";
import { Home } from "@pages/Home/Home";
import { Landing } from "@pages/Landing/Landing";
import { LandingTracker } from "@pages/LandingTracker/LandingTracker";
import { PartnerAddRequest } from "@pages/PartnerAddRequest/PartnerAddRequest";
import { PartnerBid } from "@pages/PartnerBid/PartnerBid";
import { PartnerEmployeeReport } from "@pages/PartnerEmployeeReport/PartnerEmployeeReport";
@ -13,9 +18,13 @@ import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties";
import { PartnerCategories } from "@pages/PartnerСategories/PartnerСategories";
import { Profile } from "@pages/Profile/Profile";
import { ProjectTracker } from "@pages/ProjectTracker/ProjectTracker";
import { Stack } from "@pages/Stack/Stack";
import Statistics from "@pages/Statistics/Statistics";
import { Summary } from "@pages/Summary/Summary";
import { Tracker } from "@pages/Tracker/Tracker";
import { TrackerIntro } from "@pages/TrackerIntro/TrackerIntro";
import { ViewReport } from "@pages/ViewReport/ViewReport";
import { WelcomePage } from "@pages/WelcomePage/WelcomePage";
import { Calendar } from "@components/Calendar/Calendar";
import { Candidate } from "@components/Candidate/Candidate";
@ -23,6 +32,16 @@ import { Candidate } from "@components/Candidate/Candidate";
export const PartnerPage = () => {
return (
<Routes>
<Route exact path="/auth" element={<Auth />} />
<Route exact path="/welcome-page" element={<WelcomePage />} />
<Route exact path="/stack" element={<Stack />} />
<Route exact path="/landing-tracker" element={<LandingTracker />} />
<Route exact path="/" element={<Landing />} />
<Route path="*" element={<Navigate to="/auth" replace />} />
<Route exact path="/tracker-intro" element={<TrackerIntro />} />
<Route exact path="/forms" element={<Forms />} />
<Route exact path="/company" element={<CompanyInfo />} />
<Route exact path="/candidate/:id" element={<Candidate />} />
<Route exact path="/candidate/:id/form" element={<FormPage />} />
<Route path="/:userId/calendar" element={<Calendar />} />
@ -46,6 +65,7 @@ export const PartnerPage = () => {
<Route exact path="requests-edit" element={<PartnerAddRequest />} />
<Route exact path="requests-bid" element={<PartnerBid />} />
<Route exact path="employees" element={<PartnerCategories />} />
<Route exact path="summary/:id" element={<Summary />} />
<Route
exact
path="employees/report/:uuid"