32 Commits

Author SHA1 Message Date
214d309ffb partner categories fixes 2024-08-09 21:09:02 +03:00
a156557d57 partner categories fixes 2024-08-09 21:08:56 +03:00
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
988b5e65b0 employees table 2024-07-26 20:07:43 +03:00
a6981f90b2 employees table 2024-07-26 20:07:35 +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
399abc6668 employees table 2024-07-26 19:54:06 +03:00
db5896d29b employees table 2024-07-26 19:53:57 +03:00
4697383bf3 empty page 2024-07-26 18:16:32 +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
687d9661a3 fix 2024-07-21 16:40:53 +03:00
3f7bab3353 Merge pull request 'vacancy' (#38) from vacancy into main
Reviewed-on: #38
2024-07-21 16:38:59 +03:00
dc065f3bdd vacancy 2024-07-21 16:38:06 +03:00
a561ed83c4 vacancy 2024-07-21 16:37:39 +03:00
268ff58ccd Merge pull request 'summary_fix' (#37) from summary_fix into main
Reviewed-on: #37
2024-07-18 17:27:55 +03:00
64 changed files with 2564 additions and 692 deletions

View File

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.4339 2.66676H7.24725L7.03392 2.0001C6.89562 1.60892 6.63908 1.27043 6.29985 1.03154C5.96062 0.792642 5.55549 0.665163 5.14059 0.666763H2.10059C1.57015 0.666763 1.06145 0.877477 0.686373 1.25255C0.3113 1.62762 0.100586 2.13633 0.100586 2.66676V11.3334C0.100586 11.8639 0.3113 12.3726 0.686373 12.7476C1.06145 13.1227 1.57015 13.3334 2.10059 13.3334H11.4339C11.9644 13.3334 12.4731 13.1227 12.8481 12.7476C13.2232 12.3726 13.4339 11.8639 13.4339 11.3334V4.66676C13.4339 4.13633 13.2232 3.62762 12.8481 3.25255C12.4731 2.87748 11.9644 2.66676 11.4339 2.66676ZM12.1006 11.3334C12.1006 11.5102 12.0303 11.6798 11.9053 11.8048C11.7803 11.9299 11.6107 12.0001 11.4339 12.0001H2.10059C1.92378 12.0001 1.75421 11.9299 1.62918 11.8048C1.50416 11.6798 1.43392 11.5102 1.43392 11.3334V2.66676C1.43392 2.48995 1.50416 2.32038 1.62918 2.19536C1.75421 2.07033 1.92378 2.0001 2.10059 2.0001H5.14059C5.28035 1.99974 5.41669 2.04331 5.53034 2.12466C5.64399 2.20601 5.7292 2.32102 5.77392 2.45343L6.13392 3.54676C6.17864 3.67918 6.26385 3.79419 6.3775 3.87553C6.49115 3.95688 6.62749 4.00046 6.76725 4.0001H11.4339C11.6107 4.0001 11.7803 4.07033 11.9053 4.19536C12.0303 4.32038 12.1006 4.48995 12.1006 4.66676V11.3334Z" fill="#52B709"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.62109 12.928H2.62109C2.44428 12.928 2.27471 12.8577 2.14969 12.7327C2.02467 12.6077 1.95443 12.4381 1.95443 12.2613V2.92798C1.95443 2.75117 2.02467 2.5816 2.14969 2.45657C2.27471 2.33155 2.44428 2.26131 2.62109 2.26131H5.95443V4.26131C5.95443 4.79174 6.16514 5.30045 6.54021 5.67553C6.91529 6.0506 7.42399 6.26131 7.95443 6.26131H9.95443V9.59465C9.95443 9.77146 10.0247 9.94103 10.1497 10.066C10.2747 10.1911 10.4443 10.2613 10.6211 10.2613C10.7979 10.2613 10.9675 10.1911 11.0925 10.066C11.2175 9.94103 11.2878 9.77146 11.2878 9.59465V5.59465C11.2878 5.59465 11.2878 5.59465 11.2878 5.55465C11.2808 5.4934 11.2674 5.43307 11.2478 5.37465V5.31465C11.2157 5.2461 11.1729 5.18309 11.1211 5.12798L7.12109 1.12798C7.06598 1.07612 7.00297 1.03337 6.93443 1.00131C6.91237 0.997451 6.88982 0.997451 6.86776 1.00131C6.80294 0.966647 6.73327 0.941927 6.66109 0.927979H2.62109C2.09066 0.927979 1.58195 1.13869 1.20688 1.51377C0.831807 1.88884 0.621094 2.39755 0.621094 2.92798V12.2613C0.621094 12.7917 0.831807 13.3005 1.20688 13.6755C1.58195 14.0506 2.09066 14.2613 2.62109 14.2613H6.62109C6.7979 14.2613 6.96747 14.1911 7.0925 14.0661C7.21752 13.941 7.28776 13.7715 7.28776 13.5946C7.28776 13.4178 7.21752 13.2483 7.0925 13.1232C6.96747 12.9982 6.7979 12.928 6.62109 12.928ZM7.28776 3.20131L9.01443 4.92798H7.95443C7.77762 4.92798 7.60805 4.85774 7.48302 4.73272C7.358 4.60769 7.28776 4.43812 7.28776 4.26131V3.20131ZM3.95443 8.92798H7.95443C8.13124 8.92798 8.30081 8.85774 8.42583 8.73272C8.55086 8.60769 8.62109 8.43812 8.62109 8.26131C8.62109 8.0845 8.55086 7.91493 8.42583 7.78991C8.30081 7.66488 8.13124 7.59465 7.95443 7.59465H3.95443C3.77762 7.59465 3.60805 7.66488 3.48302 7.78991C3.358 7.91493 3.28776 8.0845 3.28776 8.26131C3.28776 8.43812 3.358 8.60769 3.48302 8.73272C3.60805 8.85774 3.77762 8.92798 3.95443 8.92798ZM6.62109 10.2613H3.95443C3.77762 10.2613 3.60805 10.3315 3.48302 10.4566C3.358 10.5816 3.28776 10.7512 3.28776 10.928C3.28776 11.1048 3.358 11.2744 3.48302 11.3994C3.60805 11.5244 3.77762 11.5946 3.95443 11.5946H6.62109C6.7979 11.5946 6.96747 11.5244 7.0925 11.3994C7.21752 11.2744 7.28776 11.1048 7.28776 10.928C7.28776 10.7512 7.21752 10.5816 7.0925 10.4566C6.96747 10.3315 6.7979 10.2613 6.62109 10.2613ZM3.95443 6.26131H4.62109C4.7979 6.26131 4.96747 6.19107 5.0925 6.06605C5.21752 5.94103 5.28776 5.77146 5.28776 5.59465C5.28776 5.41783 5.21752 5.24827 5.0925 5.12324C4.96747 4.99822 4.7979 4.92798 4.62109 4.92798H3.95443C3.77762 4.92798 3.60805 4.99822 3.48302 5.12324C3.358 5.24827 3.28776 5.41783 3.28776 5.59465C3.28776 5.77146 3.358 5.94103 3.48302 6.06605C3.60805 6.19107 3.77762 6.26131 3.95443 6.26131ZM13.0944 10.4546C13.0325 10.3922 12.9587 10.3426 12.8775 10.3087C12.7962 10.2749 12.7091 10.2574 12.6211 10.2574C12.5331 10.2574 12.4459 10.2749 12.3647 10.3087C12.2835 10.3426 12.2097 10.3922 12.1478 10.4546L9.95443 12.6546L9.09443 11.788C9.03227 11.7258 8.95848 11.6765 8.87726 11.6429C8.79605 11.6092 8.709 11.5919 8.62109 11.5919C8.53319 11.5919 8.44614 11.6092 8.36493 11.6429C8.28371 11.6765 8.20992 11.7258 8.14776 11.788C8.0856 11.8501 8.03629 11.9239 8.00265 12.0051C7.96901 12.0864 7.9517 12.1734 7.9517 12.2613C7.9517 12.3492 7.96901 12.4363 8.00265 12.5175C8.03629 12.5987 8.0856 12.6725 8.14776 12.7346L9.48109 14.068C9.54307 14.1305 9.6168 14.1801 9.69804 14.2139C9.77928 14.2478 9.86642 14.2652 9.95443 14.2652C10.0424 14.2652 10.1296 14.2478 10.2108 14.2139C10.2921 14.1801 10.3658 14.1305 10.4278 14.068L13.0944 11.4013C13.1569 11.3393 13.2065 11.2656 13.2404 11.1844C13.2742 11.1031 13.2916 11.016 13.2916 10.928C13.2916 10.84 13.2742 10.7528 13.2404 10.6716C13.2065 10.5904 13.1569 10.5166 13.0944 10.4546Z" fill="#52B709"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

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

View 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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.1 MiB

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

View File

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

View File

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

View File

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

View File

@ -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. Все права защищены

View File

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

View File

@ -0,0 +1,22 @@
import React from "react";
import { Link } from "react-router-dom";
import empty from "assets/images/emptyPage.svg";
import "./emptyBlock.scss";
export const EmptyBlock = () => {
return (
<>
<div className="empty-block">
<h4 className="empty-block__title">
Данная страница находится в разработке
</h4>
<Link className="empty-block__back" to="/profile">
На главную
</Link>
</div>
<img src={empty} alt="img" className="empty-block__img" />
</>
);
};

View File

@ -0,0 +1,53 @@
.empty-block {
position: relative;
border-radius: 8px;
border: 0.5px solid;
border-image-source: linear-gradient(137.79deg, #FFFFFF 9.15%, #F4F4F4 76.22%);
background: linear-gradient(110.06deg, rgba(255, 255, 255, 0.34) 0%, rgba(239, 239, 239, 0.34) 99.25%);
display: flex;
box-shadow: 10px 9px 14.3px 0px #00000008;
align-items: center;
justify-content: center;
margin-top: 22px;
padding: 95px 0 40px;
flex-direction: column;
z-index: 2;
backdrop-filter: blur(5px);
&__img {
position: absolute;
z-index: 1;
top: 30px;
transform: translate(-50%);
left: 50%;
}
&__title {
color: #000000;
font-weight: 700;
font-size: 22px;
line-height: 32px;
margin-bottom: 0;
}
&__back {
max-width: 150px;
width: 100%;
background: #52B709;
border-radius: 44px;
color: #FFFFFF;
font-size: 14px;
font-weight: 700;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: center;
height: 40px;
transition: all 0.3s ease;
&:hover {
color: white;
scale: 1.1;
}
}
}

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: 1px solid #dde2e4;
border-radius: 8px; border-radius: 8px;
width: 60%; width: 60%;
font-family: "LabGrotesque", sans-serif;
@media (max-width: 1375px) { @media (max-width: 1375px) {
width: 80%; width: 80%;
@ -110,7 +111,14 @@
border-radius: 8px; border-radius: 8px;
border: none; border: none;
margin-bottom: 5px; 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 { .input-container {

View File

@ -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,82 +382,111 @@ export const ModalTiсket = ({
} }
useEffect(() => { useEffect(() => {
initListeners(); if (active) {
apiRequest( setStartDate(task.dead_line ? new Date(task.dead_line) : new Date());
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}` setTaskPriority(task.execution_priority);
).then((res) => { setMembers(task.taskUsers);
const comments = res.reduce((acc, cur) => { setTaskTags(task.mark);
if (!cur.parent_id) { setExecutorId(task.executor_id);
acc.push({ ...cur, subComments: [] }); setDeadLine(task.dead_line);
} else { setExecutor(task.executor);
acc.forEach((item) => { setInputsValue({
if (item.id === cur.parent_id) item.subComments.push(cur); title: task.title,
}); description: task.description,
} comment: ""
return acc; });
}, []);
setComments(comments); initListeners();
});
apiRequest(`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`).then( apiRequest(
(res) => { `/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
let timerSeconds = 0; ).then((res) => {
res.length && const comments = res.reduce((acc, cur) => {
res.forEach((time) => { if (!cur.parent_id) {
timerSeconds += time.deltaSeconds; acc.push({ ...cur, subComments: [] });
setCurrentTimerCount({ } else {
hours: Math.floor(timerSeconds / 60 / 60), acc.forEach((item) => {
minute: Math.floor((timerSeconds / 60) % 60), if (item.id === cur.parent_id) item.subComments.push(cur);
seconds: timerSeconds % 60
}); });
updateTimerHours = Math.floor(timerSeconds / 60 / 60); }
updateTimerMinute = Math.floor((timerSeconds / 60) % 60); return acc;
updateTimerSec = timerSeconds % 60; }, []);
if (!time.stopped_at) { setComments(comments);
setTimerStart(true); });
startTimer();
setTimerInfo(time);
}
});
}
);
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then( apiRequest(
(res) => { `/timer/get-by-entity?entity_type=2&entity_id=${task.id}`
).then((res) => {
if (Array.isArray(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 ( if (!time.stopped_at) {
localStorage.getItem("role_status") !== "18" && setTimerStart(true);
Boolean( 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( !correctProjectUsers.find(
(item) => item.user_id === profileInfo.id_user (item) => item.user_id === profileInfo.id_user
) )
) ) {
) { setCorrectProjectUsers((prevState) => [
setCorrectProjectUsers((prevState) => [ ...prevState,
...prevState, {
{ user: {
user: { avatar: profileInfo.photo,
avatar: profileInfo.photo, fio: profileInfo.fio
fio: profileInfo.fio },
}, user_id: profileInfo.id_user
user_id: profileInfo.id_user }
} ]);
]); }
} }
}, []); }, [active]);
useEffect(() => { useEffect(() => {
let tagIds = taskTags.map((tag) => tag.id); if (Array.isArray(taskTags)) {
setCorrectProjectTags( const tagIds = taskTags.map((tag) => tag.id);
projectMarks.reduce((acc, cur) => { setCorrectProjectTags(
if (!tagIds.includes(cur.id)) acc.push(cur); projectMarks.reduce((acc, cur) => {
return acc; if (!tagIds.includes(cur.id)) acc.push(cur);
}, []) 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)) {
setUsers( const ids = members.map((user) => user.user_id);
projectUsers.reduce((acc, cur) => { setUsers(
if (!ids.includes(cur.user_id)) acc.push(cur); projectUsers.reduce((acc, cur) => {
return acc; if (!ids.includes(cur.user_id)) acc.push(cur);
}, []) 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,23 +1042,24 @@ 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) &&
return ( taskTags.map((tag) => {
<div return (
className="tags__selected__item" <div
key={tag.id} className="tags__selected__item"
style={{ background: tag.color }} key={tag.id}
> style={{ background: tag.color }}
<p>{tag.slug}</p> >
<img <p>{tag.slug}</p>
src={crossWhite} <img
className="delete" src={crossWhite}
alt="delete" className="delete"
onClick={() => deleteTagFromTask(tag.id)} alt="delete"
/> onClick={() => deleteTagFromTask(tag.id)}
</div> />
); </div>
})} );
})}
</div> </div>
<div <div
className="tags__select" className="tags__select"

View File

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

View File

@ -331,6 +331,7 @@ export const TrackerModal = ({
status: 19 status: 19
} }
}).then((res) => { }).then((res) => {
console.log(res);
if (!Array.isArray(res.name)) { if (!Array.isArray(res.name)) {
const result = { ...res, columns: [] }; const result = { ...res, columns: [] };
dispatch(setProject(result)); dispatch(setProject(result));
@ -625,7 +626,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();

View File

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

View File

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

View File

@ -19,8 +19,17 @@
.summary__info { .summary__info {
padding-right: 25px; padding-right: 25px;
@media (max-width: 500px) { @media (max-width: 760px) {
padding-right: 5px; 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 { .summary__skill {
@ -32,6 +41,12 @@
align-items: center; align-items: center;
column-gap: 10px; column-gap: 10px;
p {
@media (max-width: 425px) {
display: none;
}
}
div { div {
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;

View File

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

View File

@ -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>

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

View File

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

View File

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

View File

@ -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();

View 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>
);
};

View 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;
}
}

View 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>
);
};

View 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;
}
}

View File

@ -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>

View File

@ -5,6 +5,7 @@ import { Link, NavLink } from "react-router-dom";
import { BurgerButton } from "@components/BurgerMenu/burgerButton"; import { BurgerButton } from "@components/BurgerMenu/burgerButton";
import { BurgerMenu } from "@components/BurgerMenu/burgerMenu"; import { BurgerMenu } from "@components/BurgerMenu/burgerMenu";
import { Footer } from "@components/Common/Footer/Footer"; import { Footer } from "@components/Common/Footer/Footer";
import ModalAuth from "@components/Modal/ModalAuth/ModalAuth";
import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration"; import ModalRegistration from "@components/Modal/ModalRegistration/ModalRegistration";
import arrow from "assets/icons/arrows/arrowLanding.svg"; 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 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";
export const Landing = () => { export const Landing = () => {
const [modalReg, setModalReg] = useState(false); const [modalReg, setModalReg] = useState(false);
const [modalAuth, setModalAuth] = useState(false);
const [menuActive, setMenuActive] = useState(false); const [menuActive, setMenuActive] = useState(false);
const opportunities = [ const opportunities = [
@ -29,22 +35,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: "Все наши предложения",
@ -57,14 +63,20 @@ export const Landing = () => {
return ( return (
<section className="landing"> <section className="landing">
<ModalRegistration active={modalReg} setActive={setModalReg} /> <ModalRegistration active={modalReg} setActive={setModalReg} />
<ModalAuth active={modalAuth} setActive={setModalAuth} />
<BurgerMenu active={menuActive} /> <BurgerMenu active={menuActive} />
<div className="landing__container"> <div className="landing__container">
<div className="landing__head"> <div className="landing__head">
<h2 className="head__logo">ITGUILD</h2> <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 <div
className="head__signUp" className="head__signUp"
onClick={(e) => { onClick={(e) => {

View File

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

View File

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

View File

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

View File

@ -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 />

View File

@ -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;
}
}

View File

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

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { apiRequest } from "@api/request"; import { apiRequest } from "@api/request";
@ -11,6 +11,7 @@ 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 tgSettingsIcon from "assets/icons/tgSettingsIcon.svg";
import astral from "assets/images/logo/astralLogo.png"; import astral from "assets/images/logo/astralLogo.png";
import kontur from "assets/images/logo/konturLogo.png"; import kontur from "assets/images/logo/konturLogo.png";
@ -18,6 +19,7 @@ import "./partnerSettings.scss";
export const PartnerSettings = () => { export const PartnerSettings = () => {
const { showNotification } = useNotification(); const { showNotification } = useNotification();
const [tgToken, setTgToken] = useState();
const [inputsValue, setInputsValue] = useState({ const [inputsValue, setInputsValue] = useState({
name: "", name: "",
oldPassword: "", oldPassword: "",
@ -30,6 +32,15 @@ export const PartnerSettings = () => {
}); });
const [loader, setLoader] = useState(false); 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 = () => { const setSettings = () => {
if (inputsValue.name.length < 2) { 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 ( return (
<div className="settings"> <div className="settings">
<ProfileHeader /> <ProfileHeader />
@ -183,6 +212,34 @@ export const PartnerSettings = () => {
использования персональных данных использования персональных данных
</span> </span>
</div> </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"> {/* <div className="partner-settings__report">
<h3 className="settings__title">Документы и отчеты</h3> <h3 className="settings__title">Документы и отчеты</h3>
<p className="settings__label">Изменить провадера ЭДО</p> <p className="settings__label">Изменить провадера ЭДО</p>

View File

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

View File

@ -17,25 +17,12 @@ import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadc
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader"; import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import rightArrow from "assets/icons/arrows/arrowRight.svg"; import rightArrow from "assets/icons/arrows/arrowRight.svg";
import folder from "assets/icons/folder.svg";
import report from "assets/icons/report.svg";
// import PartnerPersonCard from "@components/PartnerPersonCard/PartnerPersonCard";
// import { useDispatch } from "react-redux";
// import { setPartnerEmployees } from "@redux/outstaffingSlice";
// import rightArrow from "assets/icons/arrows/arrowRight.svg";
// import avatarImg from "assets/images/avatarMok.png";
// import AdminImg from "assets/images/partnerProfile/PersonalAdmin.svg";
// import ArchitectureImg from "assets/images/partnerProfile/PersonalArchitecture.svg";
// import CopyImg from "assets/images/partnerProfile/PersonalCopy.svg";
// import DesignImg from "assets/images/partnerProfile/PersonalDesign.svg";
// import FrontendImg from "assets/images/partnerProfile/PersonalFrontend.svg";
// import ManageImg from "assets/images/partnerProfile/PersonalMng.svg";
// import SmmImg from "assets/images/partnerProfile/PersonalSMM.svg";
// import TestImg from "assets/images/partnerProfile/PersonalTesters.svg";
// import BackEndImg from "assets/images/partnerProfile/personalBackEnd.svg";
import "./partnerСategories.scss"; import "./partnerСategories.scss";
export const PartnerCategories = () => { export const PartnerCategories = () => {
// const dispatch = useDispatch();
if (localStorage.getItem("role_status") !== "18") { if (localStorage.getItem("role_status") !== "18") {
return <Navigate to="/profile" replace />; return <Navigate to="/profile" replace />;
} }
@ -44,34 +31,62 @@ export const PartnerCategories = () => {
const theme = useTheme(getTheme()); const theme = useTheme(getTheme());
const [nodes, setNodes] = useState([]); const [nodes, setNodes] = useState([]);
const [initialNodes, setInitialNodes] = useState([]); const [initialNodes, setInitialNodes] = useState([]);
const [activeTab, setActiveTab] = useState(0);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const tabs = [
{
name: "Фронтенд",
value: 2
},
{
name: "Бэкенд",
value: 1
}
];
const COLUMNS = [ const COLUMNS = [
{ {
label: "", label: "",
renderCell: (item) => ( renderCell: (item) => (
<img <Link to={`/profile/summary/${item.user_id}`}>
className="table__avatar" <img
src={urlForLocal(item?.employee.avatar)} className="table__avatar"
alt="avatar" src={urlForLocal(item?.employee.avatar)}
/> alt="avatar"
/>
</Link>
) )
}, },
{ {
label: "ФИО", label: "Данные",
renderCell: (item) => <p>{item?.employee.fio}</p>, renderCell: (item) => (
sort: { sortKey: "NAME" } <Link className="table__info" to={`/profile/summary/${item.user_id}`}>
<p>{item?.employee.fio}</p>
<span>
{item?.employee.level_title} / {item?.employee.position.name}
</span>
</Link>
)
}, },
{ {
label: "Резюме", label: "Участвует в проекте",
renderCell: (item) => ( renderCell: (item) => (
<Link className="table__link" to={`/candidate/${item.user_id}`}> <div className="table__project">
Резюме {item?.employee.projects.length ? (
<div className="img__wrapper"> item.employee.projects.map((project) => {
<img src={rightArrow} alt="arrow" /> return (
</div> <div className="table__project__item" key={project.id}>
</Link> <img src={folder} alt="folder" />{" "}
<p>{project.project.name}</p>
</div>
);
})
) : (
<span>Нет проектов</span>
)}
</div>
) )
}, },
{ {
@ -81,12 +96,17 @@ export const PartnerCategories = () => {
className="table__link" className="table__link"
to={`/profile/employees/report/${item.user_id}`} to={`/profile/employees/report/${item.user_id}`}
> >
<img src={report} alt="report" />
Подробный отчет Подробный отчет
<div className="img__wrapper"> <div className="img__wrapper">
<img src={rightArrow} alt="arrow" /> <img src={rightArrow} alt="arrow" />
</div> </div>
</Link> </Link>
) )
},
{
label: <span className="table__action">Действие</span>,
renderCell: () => <div className="table__more"></div>
} }
]; ];
@ -115,9 +135,9 @@ export const PartnerCategories = () => {
useEffect(() => { useEffect(() => {
setLoader(true); setLoader(true);
apiRequest("/project/my-employee").then((el) => { apiRequest("/project/my-employee").then((el) => {
setLoader(false); setNodes(el.managerEmployees);
setNodes(el?.managerEmployees);
setInitialNodes(el.managerEmployees); setInitialNodes(el.managerEmployees);
setLoader(false);
}); });
}, []); }, []);
@ -136,108 +156,6 @@ export const PartnerCategories = () => {
console.log(action, state); console.log(action, state);
} }
// const [personalInfoItems] = useState([
// {
// title: "Backend разработчики",
// link: "/profile/categories/employees",
// description:
// "Java PHP Python C# React Vue.js NodeJs Golang Ruby JavaScript",
// available: true,
// img: BackEndImg
// },
// {
// title: "Frontend разработчики",
// link: "/profile/categories/employees",
// description:
// "Java PHP Python C# React Vue.js NodeJs Golang Ruby JavaScript",
// available: true,
// img: FrontendImg
// },
// {
// title: "Архитектура проектов",
// link: "/profile/categories/employees",
// description: "Потоки данных ER ERP CRM CQRS UML BPMN",
// available: true,
// img: ArchitectureImg
// },
// {
// title: "Дизайн проектов",
// link: "/profile/categories/employees",
// description:
// "Java PHP Python C# React Vue.js NodeJs Golang Ruby JavaScript",
// available: true,
// img: DesignImg
// },
// {
// title: "Тестирование проектов",
// link: "/profile/add-request",
// description: "SQL Postman TestRail Kibana Ручное тестирование",
// available: false,
// img: TestImg
// },
// {
// title: "Администрирование проектов",
// link: "/profile/add-request",
// description: "DevOps ELK Kubernetes Docker Bash Apache Oracle Git",
// available: false,
// img: AdminImg
// },
// {
// title: "Управление проектом",
// link: "/profile/add-request",
// description: "Scrum Kanban Agile Miro CustDev",
// available: false,
// img: ManageImg
// },
// {
// title: "Копирайтинг проектов",
// link: "/profile/add-request",
// description: "Теги Заголовок H1 Дескриптор Абзац Сценарий",
// available: false,
// img: CopyImg
// },
// {
// title: "Реклама и SMM",
// link: "/profile/add-request",
// description:
// "Java PHP Python C# React Vue.js NodeJs Golang Ruby JavaScript",
// available: false,
// img: SmmImg
// }
// ]);
// const [mokPersons] = useState([
// {
// personAvatar: avatarImg,
// name: "Макаренко Дмитрий",
// qualification: "PHP Backend - разработчик",
// level: "Middle",
// project: "Админка НВД Консалтинг",
// tasks_in_progress: 5,
// month_hours: 140,
// id: 1
// },
// {
// personAvatar: avatarImg,
// name: "Макаренко Дмитрий",
// qualification: "PHP Backend - разработчик",
// level: "Middle",
// project: "Админка НВД Консалтинг",
// tasks_in_progress: 5,
// month_hours: 140,
// id: 2
// },
// {
// personAvatar: avatarImg,
// name: "Макаренко Дмитрий",
// qualification: "PHP Backend - разработчик",
// level: "Middle",
// project: "Админка НВД Консалтинг",
// tasks_in_progress: 5,
// month_hours: 140,
// id: 3
// }
// ]);
return ( return (
<div className="partner-categories"> <div className="partner-categories">
<ProfileHeader /> <ProfileHeader />
@ -266,6 +184,43 @@ export const PartnerCategories = () => {
onChange={handleSearch} onChange={handleSearch}
/> />
</label> </label>
<div className="table__tabs">
<div
onClick={() => {
setActiveTab(0);
setNodes(initialNodes);
}}
className={
activeTab === 0
? "table__tab table__tab--active"
: "table__tab"
}
>
Все
</div>
{tabs.map((tab) => {
return (
<div
onClick={() => {
setActiveTab(tab.name);
setNodes(
initialNodes.filter(
(item) => item.employee.position.id === tab.value
)
);
}}
className={
activeTab === tab.name
? "table__tab table__tab--active"
: "table__tab"
}
key={tab.value}
>
{tab.name}
</div>
);
})}
</div>
<CompactTable <CompactTable
columns={COLUMNS} columns={COLUMNS}
data={data} data={data}
@ -273,54 +228,61 @@ export const PartnerCategories = () => {
sort={sort} sort={sort}
pagination={pagination} pagination={pagination}
/> />
<div className="table__pagination"> {Boolean(nodes.length) &&
<button pagination.state.getPages(data.nodes).length > 1 && (
className={ <div className="table__pagination">
pagination.state.page === 0 ? "switch disable" : "switch"
}
type="button"
disabled={pagination.state.page === 0}
onClick={() =>
pagination.fns.onSetPage(pagination.state.page - 1)
}
>
{"<"}
</button>
<span className="table__pages">
{pagination.state.getPages(data.nodes).map((_, index) => (
<button <button
key={index}
type="button"
className={ className={
pagination.state.page === index pagination.state.page === 0
? "page page--active " ? "switch disable"
: "page" : "switch"
}
type="button"
disabled={pagination.state.page === 0}
onClick={() =>
pagination.fns.onSetPage(pagination.state.page - 1)
} }
onClick={() => pagination.fns.onSetPage(index)}
> >
{index + 1} {"<"}
</button> </button>
))} <span className="table__pages">
</span> {pagination.state
<button .getPages(data.nodes)
className={ .map((_, index) => (
pagination.state.page + 1 === <button
pagination.state.getPages(data.nodes).length key={index}
? "switch disable" type="button"
: "switch" className={
} pagination.state.page === index
type="button" ? "page page--active "
disabled={ : "page"
pagination.state.page + 1 === }
pagination.state.getPages(data.nodes).length onClick={() => pagination.fns.onSetPage(index)}
} >
onClick={() => {index + 1}
pagination.fns.onSetPage(pagination.state.page + 1) </button>
} ))}
> </span>
{">"} <button
</button> className={
</div> pagination.state.page + 1 ===
pagination.state.getPages(data.nodes).length
? "switch disable"
: "switch"
}
type="button"
disabled={
pagination.state.page + 1 ===
pagination.state.getPages(data.nodes).length
}
onClick={() =>
pagination.fns.onSetPage(pagination.state.page + 1)
}
>
{">"}
</button>
</div>
)}
</> </>
) : ( ) : (
<div className="partner-categories__empty"> <div className="partner-categories__empty">
@ -331,39 +293,6 @@ export const PartnerCategories = () => {
</Link> </Link>
</div> </div>
)} )}
{/*{personalInfoItems.map((item, index) => {*/}
{/* return (*/}
{/* <Link*/}
{/* to={item.link}*/}
{/* key={index}*/}
{/* className={*/}
{/* item.available*/}
{/* ? "partner-categories__item item"*/}
{/* : "partner-categories__item item item__disable"*/}
{/* }*/}
{/* onClick={() => {*/}
{/* dispatch(setPartnerEmployees(mokPersons));*/}
{/* }}*/}
{/* >*/}
{/* <div className="item__title">*/}
{/* <img src={item.img} alt={item.title} />*/}
{/* <h4>{item.title}</h4>*/}
{/* </div>*/}
{/* <div className="item__info">*/}
{/* <p>{item.description}</p>*/}
{/* <div className="more">*/}
{/* <img src={rightArrow} alt="arrow" />*/}
{/* </div>*/}
{/* </div>*/}
{/* {!item.available && (*/}
{/* <div className="item__disable-hover">*/}
{/* <p>У вас нет персонала из категории</p>*/}
{/* <button>Подобрать</button>*/}
{/* </div>*/}
{/* )}*/}
{/* </Link>*/}
{/* );*/}
{/*})}*/}
</div> </div>
)} )}
</div> </div>

View File

@ -178,10 +178,56 @@
} }
} }
&__tabs {
display: flex;
margin: 0 auto 30px 18px;
padding: 4px 8px;
gap: 10px;
align-items: center;
font-size: 16px;
background: rgba(240, 242, 245, 1);
border-radius: 5px;
}
&__tab {
padding: 8px 12px;
cursor: pointer;
color: rgba(46, 58, 89, 1);
font-size: 15px;
&--active {
background: rgba(255, 255, 255, 1);
font-size: 16px;
border-radius: 5px;
border: 0;
}
&:nth-child(2) {
border-right: 1px solid rgba(224, 226, 229, 1);
border-left: 1px solid rgba(224, 226, 229, 1);
}
}
&__avatar { &__avatar {
max-width: 45px; width: 40px;
height: 40px;
margin-left: 18px;
} }
&__info {
p {
color: rgba(46, 58, 89, 1);
font-size: 14px;
font-weight: 500;
line-height: 17.5px;
}
span {
color: rgba(155, 171, 197, 1);
font-size: 14px;
line-height: 17.5px;
}
}
&__link { &__link {
display: flex; display: flex;
column-gap: 10px; column-gap: 10px;
@ -199,11 +245,76 @@
justify-content: center; justify-content: center;
img { img {
width: 14px; width: 8px;
} }
} }
} }
&__project {
color: rgba(46, 58, 89, 1);
font-size: 14px;
font-weight: 500;
line-height: 17.5px;
display: flex;
flex-wrap: wrap;
gap: 11px;
&__item {
border-radius: 5px;
padding: 8px;
color: rgba(46, 58, 89, 1);
font-size: 14px;
border: 1px solid rgba(237, 237, 237, 1);
display: flex;
gap: 8px;
p {
max-width: 100px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
&__action {
color: rgba(155, 171, 197, 1);
font-size: 14px;
font-weight: 400;
}
&__more {
position: relative;
height: 30px;
cursor: pointer;
width: 10px;
display: flex;
align-items: center;
justify-content: space-evenly;
flex-direction: column;
&:before {
content: '';
display: flex;
top: 2px;
width: 4px;
height: 4px;
background: rgba(155, 171, 197, 1);
border-radius: 50px;
position: relative;
}
&:after {
content: '';
display: flex;
bottom: 2px;
width: 4px;
height: 4px;
background: rgba(155, 171, 197, 1);
border-radius: 50px;
position: relative;
}
}
&__pagination { &__pagination {
width: 100%; width: 100%;
display: flex; display: flex;
@ -251,6 +362,7 @@
} }
table { table {
--data-table-library_grid-template-columns: minmax(0px, 0.5fr) minmax(0px, 1.5fr) minmax(0px, 1fr) minmax(0px, 1fr) minmax(0px, 1fr) !important;
th { th {
border-top: 0; border-top: 0;
border-bottom: 1px solid #EDEDED; border-bottom: 1px solid #EDEDED;

View File

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

View File

@ -9,5 +9,13 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
margin-top: 23px;
}
&__title {
font-weight: 700;
font-size: 22px;
line-height: 32px;
color: #000000;
} }
} }

View File

@ -1,7 +1,7 @@
import moment from "moment"; import moment from "moment";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Link, 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,19 +448,16 @@ export const ProjectTracker = () => {
</Link> </Link>
</div> </div>
</div> </div>
<ModalTicket
{Boolean(modalActiveTicket) && ( active={modalActiveTicket}
<ModalTicket setActive={setModalActiveTicket}
active={modalActiveTicket} task={selectedTicket}
setActive={setModalActiveTicket} projectId={projectBoard.id}
task={selectedTicket} projectName={projectBoard.name}
projectId={projectBoard.id} projectUsers={projectBoard.projectUsers}
projectName={projectBoard.name} projectOwnerId={projectBoard.owner_id}
projectUsers={projectBoard.projectUsers} projectMarks={projectBoard.mark}
projectOwnerId={projectBoard.owner_id} />
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;
}}
/> />
); );
})} })}

View File

@ -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>

View File

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

View File

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

View File

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

View 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>
);
};

View 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%;
}
}

View File

@ -1,6 +1,11 @@
import React from "react"; 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 { OpenRequest } from "@pages/OpenRequests/OpenRequest";
import { PartnerSettings } from "@pages/PartnerSettings/PartnerSettings"; import { PartnerSettings } from "@pages/PartnerSettings/PartnerSettings";
import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties"; import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties";
@ -10,10 +15,14 @@ import { ProjectTracker } from "@pages/ProjectTracker/ProjectTracker";
import { PassingTests } from "@pages/Quiz/PassingTests"; import { PassingTests } from "@pages/Quiz/PassingTests";
import { QuizPage } from "@pages/Quiz/QuizPage"; import { QuizPage } from "@pages/Quiz/QuizPage";
import { QuizReportPage } from "@pages/Quiz/QuizReportPage"; import { QuizReportPage } from "@pages/Quiz/QuizReportPage";
import { Stack } from "@pages/Stack/Stack";
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 { TrackerIntro } from "@pages/TrackerIntro/TrackerIntro";
import { Vacancy } from "@pages/Vacancy/Vacancy";
import { ViewReport } from "@pages/ViewReport/ViewReport"; import { ViewReport } from "@pages/ViewReport/ViewReport";
import { WelcomePage } from "@pages/WelcomePage/WelcomePage";
import TicketFullScreen from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen"; import TicketFullScreen from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
import { ProfileCalendar } from "@components/ProfileCalendar/ProfileCalendar"; import { ProfileCalendar } from "@components/ProfileCalendar/ProfileCalendar";
@ -22,6 +31,16 @@ import { ReportForm } from "@components/ReportForm/ReportForm";
export const DeveloperPage = () => { export const DeveloperPage = () => {
return ( return (
<Routes> <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 path="/tracker/task/:id" element={<TicketFullScreen />} />
<Route <Route
exact exact
@ -36,6 +55,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 />} />

View File

@ -1,8 +1,13 @@
import React from "react"; import React from "react";
import { Navigate, 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 { FormPage } from "@pages/FormPage/FormPage"; import { FormPage } from "@pages/FormPage/FormPage";
import { Forms } from "@pages/Forms/Forms";
import { Home } from "@pages/Home/Home"; 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 { PartnerAddRequest } from "@pages/PartnerAddRequest/PartnerAddRequest";
import { PartnerBid } from "@pages/PartnerBid/PartnerBid"; import { PartnerBid } from "@pages/PartnerBid/PartnerBid";
import { PartnerEmployeeReport } from "@pages/PartnerEmployeeReport/PartnerEmployeeReport"; 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 { PartnerCategories } from "@pages/PartnerСategories/PartnerСategories";
import { Profile } from "@pages/Profile/Profile"; import { Profile } from "@pages/Profile/Profile";
import { ProjectTracker } from "@pages/ProjectTracker/ProjectTracker"; import { ProjectTracker } from "@pages/ProjectTracker/ProjectTracker";
import { Stack } from "@pages/Stack/Stack";
import Statistics from "@pages/Statistics/Statistics"; import Statistics from "@pages/Statistics/Statistics";
import { Summary } from "@pages/Summary/Summary";
import { Tracker } from "@pages/Tracker/Tracker"; import { Tracker } from "@pages/Tracker/Tracker";
import { TrackerIntro } from "@pages/TrackerIntro/TrackerIntro";
import { ViewReport } from "@pages/ViewReport/ViewReport"; import { ViewReport } from "@pages/ViewReport/ViewReport";
import { WelcomePage } from "@pages/WelcomePage/WelcomePage";
import { Calendar } from "@components/Calendar/Calendar"; import { Calendar } from "@components/Calendar/Calendar";
import { Candidate } from "@components/Candidate/Candidate"; import { Candidate } from "@components/Candidate/Candidate";
@ -23,6 +32,16 @@ import { Candidate } from "@components/Candidate/Candidate";
export const PartnerPage = () => { export const PartnerPage = () => {
return ( return (
<Routes> <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" element={<Candidate />} />
<Route exact path="/candidate/:id/form" element={<FormPage />} /> <Route exact path="/candidate/:id/form" element={<FormPage />} />
<Route path="/:userId/calendar" element={<Calendar />} /> <Route path="/:userId/calendar" element={<Calendar />} />
@ -46,6 +65,7 @@ export const PartnerPage = () => {
<Route exact path="requests-edit" element={<PartnerAddRequest />} /> <Route exact path="requests-edit" element={<PartnerAddRequest />} />
<Route exact path="requests-bid" element={<PartnerBid />} /> <Route exact path="requests-bid" element={<PartnerBid />} />
<Route exact path="employees" element={<PartnerCategories />} /> <Route exact path="employees" element={<PartnerCategories />} />
<Route exact path="summary/:id" element={<Summary />} />
<Route <Route
exact exact
path="employees/report/:uuid" path="employees/report/:uuid"