17 Commits

Author SHA1 Message Date
16a5a1f548 partner request design 2024-05-03 19:23:46 +03:00
a763c5a69a partner request design 2024-05-03 19:23:15 +03:00
a7c58b2609 tracker tasks 2024-05-03 14:26:36 +03:00
3b8ec8e100 tracker tasks 2024-05-03 14:26:09 +03:00
94136c97e6 ProfileCalendar 2024-05-01 14:54:53 +03:00
4810412bd7 layout of the outstaffing page 2024-05-01 14:53:28 +03:00
3f46d60720 fix candidate resume 2024-04-24 19:20:21 +03:00
d49a2eb0c8 Merge pull request 'landing' (#36) from landing into main
Reviewed-on: #36
2024-04-22 19:03:38 +03:00
8de343016f stack steps 2024-04-22 19:03:00 +03:00
470bf6ec67 stack steps 2024-04-22 19:02:17 +03:00
dea1eb6104 resolve 2024-04-22 17:03:14 +03:00
ee20b49993 fix total hours 2024-04-22 17:01:37 +03:00
0e04e19c1b total day hours 2024-04-22 17:00:37 +03:00
bd4bfacd66 Add Cards in Profile 2024-04-22 16:19:40 +03:00
1bdabd32bf Merge pull request 'landing' (#35) from landing into main
Reviewed-on: #35
2024-04-22 16:04:48 +03:00
13df697614 stack projects 2024-04-18 16:42:54 +03:00
79299d1177 stack projects 2024-04-18 16:42:18 +03:00
32 changed files with 1201 additions and 334 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

View File

@ -0,0 +1,3 @@
<svg width="9" height="6" viewBox="0 0 9 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.11629 5.8584L8.07227 0.858398H0.160323L4.11629 5.8584Z" fill="#2E3A59"/>
</svg>

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -299,7 +299,7 @@
} }
.pass { .pass {
background-color: #f7d7c9 !important; background-color: #ba5c33 !important;
} }
.today { .today {
@ -308,7 +308,7 @@
} }
.selected { .selected {
background-color: #f9f9c3 !important; background-color: #cbcbb4 !important;
} }
.block { .block {

View File

@ -32,7 +32,7 @@ export const Candidate = () => {
if (localStorage.getItem("role_status") !== "18") { if (localStorage.getItem("role_status") !== "18") {
return <Navigate to="/profile" replace />; return <Navigate to="/profile" replace />;
} }
// const { id: candidateId } = useParams(); const { id: candidateId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -47,7 +47,7 @@ export const Candidate = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
apiRequest(`/user/me`, {}).then((el) => apiRequest(`/resume?userId=${candidateId}`).then((el) =>
dispatch(currentCandidate(el.userCard)) dispatch(currentCandidate(el.userCard))
); );
}, [dispatch]); }, [dispatch]);
@ -103,9 +103,7 @@ export const Candidate = () => {
link: "/profile/catalog" link: "/profile/catalog"
}, },
{ {
name: `${currentCandidateObj.specification} ${ name: `${currentCandidateObj.fio}`,
SKILLS[currentCandidateObj.position_id]
}, ${LEVELS[currentCandidateObj.level]}`,
link: `/candidate/${currentCandidateObj.id}` link: `/candidate/${currentCandidateObj.id}`
} }
]} ]}
@ -115,6 +113,7 @@ export const Candidate = () => {
<div className="col-12 candidate__header"> <div className="col-12 candidate__header">
<div className="candidate__header__left"> <div className="candidate__header__left">
<h3> <h3>
{currentCandidateObj.fio} &nbsp;{" "}
{currentCandidateObj.specification} &nbsp;{" "} {currentCandidateObj.specification} &nbsp;{" "}
{SKILLS[currentCandidateObj.position_id]} &nbsp;{" "} {SKILLS[currentCandidateObj.position_id]} &nbsp;{" "}
{LEVELS[currentCandidateObj.level]} {LEVELS[currentCandidateObj.level]}

View File

@ -10,7 +10,7 @@ export const CardControl = ({ title, path, description, img }) => {
<Link to={`/${path}`} className="control-card"> <Link to={`/${path}`} className="control-card">
<div className="control-card__about"> <div className="control-card__about">
<img src={img} alt="itemImg" /> <img src={img} alt="itemImg" />
<h3>{title}</h3> <h3 dangerouslySetInnerHTML={{ __html: title }}></h3>
</div> </div>
<div className="control-card__info"> <div className="control-card__info">
<p dangerouslySetInnerHTML={{ __html: description }}></p> <p dangerouslySetInnerHTML={{ __html: description }}></p>

View File

@ -38,7 +38,7 @@
font-weight: 500; font-weight: 500;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
max-width: 125px; max-width: 165px;
margin-bottom: 0; margin-bottom: 0;
} }
} }

View File

@ -664,11 +664,8 @@ export const ModalTiсket = ({
"EasyImage", "EasyImage",
"Image", "Image",
"ImageCaption", "ImageCaption",
"ImageStyle",
"ImageToolbar",
"ImageUpload", "ImageUpload",
"MediaEmbed", "MediaEmbed"
"BlockQuote"
] ]
}} }}
onChange={(event, editor) => { onChange={(event, editor) => {

View File

@ -683,11 +683,8 @@ export const TicketFullScreen = () => {
"EasyImage", "EasyImage",
"Image", "Image",
"ImageCaption", "ImageCaption",
"ImageStyle",
"ImageToolbar",
"ImageUpload", "ImageUpload",
"MediaEmbed", "MediaEmbed"
"BlockQuote"
] ]
}} }}
onChange={(event, editor) => { onChange={(event, editor) => {

View File

@ -624,7 +624,15 @@ export const TrackerModal = ({
"bulletedList", "bulletedList",
"numberedList" "numberedList"
], ],
removePlugins: ["BlockQuote"], removePlugins: [
"CKFinderUploadAdapter",
"CKFinder",
"EasyImage",
"Image",
"ImageCaption",
"ImageUpload",
"MediaEmbed"
],
placeholder: "Описание задачи" placeholder: "Описание задачи"
}} }}
onChange={(event, editor) => { onChange={(event, editor) => {

View File

@ -14,7 +14,6 @@ import {
import { import {
calendarHelper, calendarHelper,
correctDay, correctDay,
currentMonthAndDay,
getCorrectDate, getCorrectDate,
getReports, getReports,
hourOfNum hourOfNum
@ -29,7 +28,6 @@ import BaseButton from "@components/Common/BaseButton/BaseButton";
import arrowLeft from "assets/icons/arrows/arrowCalendar_left.png"; import arrowLeft from "assets/icons/arrows/arrowCalendar_left.png";
import arrowRight from "assets/icons/arrows/arrowCalendar_right.png"; import arrowRight from "assets/icons/arrows/arrowCalendar_right.png";
import calendarIcon from "assets/icons/calendar.svg"; import calendarIcon from "assets/icons/calendar.svg";
// import close from "assets/icons/closeProjectPersons.svg";
import rectangle from "assets/images/rectangle__calendar.png"; import rectangle from "assets/images/rectangle__calendar.png";
export const ProfileCalendarComponent = React.memo( export const ProfileCalendarComponent = React.memo(
@ -46,6 +44,7 @@ export const ProfileCalendarComponent = React.memo(
}) => { }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
// const [l, setL] = useState(1);
const [calendar, setCalendar] = useState([]); const [calendar, setCalendar] = useState([]);
const [month, setMonth] = useState(""); const [month, setMonth] = useState("");
const [endDate, setEndDate] = useState(null); const [endDate, setEndDate] = useState(null);
@ -174,9 +173,14 @@ export const ProfileCalendarComponent = React.memo(
}); });
} }
// function errorr(TotalRangeHours) { const countHours = (day) => {
// console.error(TotalRangeHours); let hours =
// } reports
.find((item) => moment(item.created_at).isSame(day, "date"))
?.task.reduce((acc, task) => acc + task.hours_spent, 0) || 0;
return `${hours} ${hourOfNum(hours)}`;
};
return ( return (
<div className="calendar-component"> <div className="calendar-component">
<div className="calendar-component__header"> <div className="calendar-component__header">
@ -265,10 +269,9 @@ export const ProfileCalendarComponent = React.memo(
<div className="form-date">{day.format("D")}</div> <div className="form-date">{day.format("D")}</div>
<div className="form-box"> <div className="form-box">
<div className="form-hours"> <div className="form-hours">
<span>7/Час</span> <span>{countHours(day)}</span>
</div> </div>
</div> </div>
{/* {currentMonthAndDay(day)} */}
</Link> </Link>
</button> </button>
)) ))

View File

@ -34,11 +34,15 @@
display: flex; display: flex;
align-items: center; align-items: center;
grid-column-gap: 30px; grid-column-gap: 30px;
column-gap: 30px; column-gap: 10px;
margin-top: 20px; margin-top: 20px;
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
img {
width: 23px;
}
p { p {
margin-bottom: 0; margin-bottom: 0;
font-size: 14px; font-size: 14px;

View File

@ -127,11 +127,8 @@ export const TrackerTaskComment = ({
"EasyImage", "EasyImage",
"Image", "Image",
"ImageCaption", "ImageCaption",
"ImageStyle",
"ImageToolbar",
"ImageUpload", "ImageUpload",
"MediaEmbed", "MediaEmbed"
"BlockQuote"
] ]
}} }}
onChange={(event, editor) => { onChange={(event, editor) => {

View File

@ -7,8 +7,6 @@ import { Footer } from "@components/Common/Footer/Footer";
import arrow from "assets/icons/arrows/arrowLanding.svg"; import arrow from "assets/icons/arrows/arrowLanding.svg";
import authIcon from "assets/icons/authIcon.svg"; import authIcon from "assets/icons/authIcon.svg";
import clue from "assets/icons/landingClue.svg"; import clue from "assets/icons/landingClue.svg";
import telegram from "assets/icons/telegramIcon.svg";
import vk from "assets/icons/vkIcon.svg";
import codeBg from "assets/images/landingBackgroundCode.svg"; import codeBg from "assets/images/landingBackgroundCode.svg";
import cat from "assets/images/landingCat.png"; import cat from "assets/images/landingCat.png";

View File

@ -34,17 +34,20 @@ export const PartnerAddRequest = () => {
const [specializationList, setSpecializationList] = useState([]); const [specializationList, setSpecializationList] = useState([]);
const [levelList, setLevelList] = useState([]); const [levelList, setLevelList] = useState([]);
const [countList] = useState([1, 2, 3, 4, 5]); const [countList] = useState([1, 2, 3, 4, 5]);
const [locationList] = useState(["РФ", "Беларусь"]);
const [openSkillsSelect, setOpenSkillsSelect] = useState(false); const [openSkillsSelect, setOpenSkillsSelect] = useState(false);
const [openSpecializationList, setOpenSpecializationListOpen] = const [openSpecializationList, setOpenSpecializationListOpen] =
useState(false); useState(false);
const [openLevelList, setOpenLevelList] = useState(false); const [openLevelList, setOpenLevelList] = useState(false);
const [openCountList, setOpenCountList] = useState(false); const [openCountList, setOpenCountList] = useState(false);
const [openLocationList, setOpenLocationList] = useState(false);
const [editRequest, setEditRequest] = useState(false); const [editRequest, setEditRequest] = useState(false);
const [selectedSkills, setSelectedSkills] = useState([]); const [selectedSkills, setSelectedSkills] = useState([]);
const [selectedSpecialization, setSelectedSpecialization] = useState( const [selectedSpecialization, setSelectedSpecialization] = useState(
"Выберите специализацию" "Выберите специализацию"
); );
const [selectedLevel, setSelectedLevel] = useState("Выберите уровень"); const [selectedLevel, setSelectedLevel] = useState("Выберите уровень");
const [selectedLocation, setSelectedLocation] = useState("Выберите локацию");
const [selectedCount, setSelectedCount] = useState( const [selectedCount, setSelectedCount] = useState(
"Выберите кол-во сотрудников" "Выберите кол-во сотрудников"
); );
@ -177,6 +180,7 @@ export const PartnerAddRequest = () => {
setOpenSpecializationListOpen(false); setOpenSpecializationListOpen(false);
setOpenLevelList(false); setOpenLevelList(false);
setOpenCountList(false); setOpenCountList(false);
setOpenLocationList(false);
} }
}; };
@ -202,280 +206,329 @@ export const PartnerAddRequest = () => {
? "Страница редактирования заявки" ? "Страница редактирования заявки"
: "Страница добавления заявки"} : "Страница добавления заявки"}
</h2> </h2>
<div className="partner-add-request__section"> <div className="partner-add-request__main">
<div className="partner-add-request__form"> <div className="partner-add-request__section">
<div className="partner-add-request__form__block form__block"> <div className="partner-add-request__form">
<h3 className="form__block__title">Данные открытой позиции</h3> <div className="partner-add-request__form__block form__block">
<div className="form__block__section"> <h3 className="form__block__title">Данные открытой позиции</h3>
<h3>Название вакансии</h3> <div className="form__block__section">
<div className="form__block__section__input"> <h3>Название вакансии</h3>
<input <div className="form__block__section__input">
value={inputs.title} <input
onChange={(e) => value={inputs.title}
setInputs((prevValue) => ({ onChange={(e) =>
...prevValue, setInputs((prevValue) => ({
title: e.target.value ...prevValue,
})) title: e.target.value
} }))
type="text" }
placeholder="Вакансия" type="text"
/> placeholder="Вакансия"
</div>
</div>
<div className="form__block__section">
<h3>Выберите специализацию</h3>
<div
className="form__block__section__selects"
onClick={() => {
setOpenSpecializationListOpen(!openSpecializationList);
}}
>
<div className="form__block__section__select">
<span>
{typeof selectedSpecialization === "string"
? selectedSpecialization
: selectedSpecialization.name}
</span>
<img
className={openSpecializationList ? "rotate" : ""}
src={arrowDown}
/> />
</div> </div>
</div> </div>
{openSpecializationList && <div className="form__block__section">
Boolean(specializationList.length) && ( <h3>Выберите специализацию</h3>
<div className="form__block__dropDown"> <div
{specializationList.map((specialization) => { className="form__block__section__selects"
onClick={() => {
setOpenSpecializationListOpen(!openSpecializationList);
}}
>
<div className="form__block__section__select">
<span>
{typeof selectedSpecialization === "string"
? selectedSpecialization
: selectedSpecialization.name}
</span>
<img
className={openSpecializationList ? "rotate" : ""}
src={arrowDown}
/>
</div>
</div>
{openSpecializationList &&
Boolean(specializationList.length) && (
<div className="form__block__dropDown">
{specializationList.map((specialization) => {
return (
<p
key={specialization.id}
onClick={() => {
setOpenSpecializationListOpen(false);
setSelectedSpecialization(specialization);
}}
>
{specialization.name}
</p>
);
})}
</div>
)}
</div>
<div className="form__block__section">
<h3>Навыки</h3>
<div
className="form__block__skills"
onClick={() => {
setOpenSkillsSelect(true);
}}
>
{Boolean(selectedSkills.length) &&
selectedSkills.map((skill, index) => {
return ( return (
<p <div className="skill" key={`selected-${skill.id}`}>
key={specialization.id} <span>{skill.name}</span>
<img
src={deleteIcon}
alt="delete"
onClick={() => {
setSkills((prevArray) => [...prevArray, skill]);
setFilteredSkills((prevArray) => [
...prevArray,
skill
]);
setSelectedSkills(
selectedSkills.filter((skill, indexSkill) => {
return indexSkill !== index;
})
);
}}
/>
</div>
);
})}
<input
type="text"
placeholder="Выберите навыки"
onChange={(e) => {
setFilteredSkills(
skills.filter((skill) => {
return skill.name
.toLowerCase()
.includes(e.target.value.toLowerCase());
})
);
}}
/>
</div>
{openSkillsSelect && Boolean(filteredSkills.length) && (
<div className="form__block__dropDown">
{filteredSkills.map((skill, index) => {
return (
<span
key={skill.id}
onClick={() => { onClick={() => {
setOpenSpecializationListOpen(false); setSelectedSkills((prevArray) => [
setSelectedSpecialization(specialization); ...prevArray,
skill
]);
setFilteredSkills(
filteredSkills.filter((skill, skillIndex) => {
return skillIndex !== index;
})
);
setSkills(
skills.filter((initSkill) => {
return initSkill.id !== skill.id;
})
);
setOpenSkillsSelect(false);
}} }}
> >
{specialization.name} {skill.name}
</span>
);
})}
</div>
)}
</div>
</div>
<div className="partner-add-request__form__block form__block">
<h3 className="form__block__title">Квалификация</h3>
<div className="form__block__section">
<h3>Выберите уровень знаний </h3>
<div
className="form__block__section__select"
onClick={() => setOpenLevelList(!openLevelList)}
>
<span>
{typeof selectedLevel === "string"
? selectedLevel
: selectedLevel.name}
</span>
<img
className={openLevelList ? "rotate" : ""}
src={arrowDown}
/>
</div>
{openLevelList &&
Boolean(Object.values(levelList).length) && (
<div className="form__block__dropDown">
{Object.values(levelList).map((level, index) => {
return (
<p
key={level}
onClick={() => {
setOpenLevelList(false);
setSelectedLevel({
name: level,
id: index + 1
});
}}
>
{level}
</p>
);
})}
</div>
)}
</div>
<div className="form__block__section">
<h3>Введите необходимое описание</h3>
<textarea
value={inputs.description}
onChange={(e) =>
setInputs((prevValue) => ({
...prevValue,
description: e.target.value
}))
}
/>
</div>
<div className="form__block__section">
<h3>Необходимое количество человек на позицию</h3>
<div
className="form__block__section__select"
onClick={() => setOpenCountList(true)}
>
<span>{selectedCount}</span>
<img
className={openCountList ? "rotate" : ""}
src={arrowDown}
/>
</div>
{openCountList && (
<div className="form__block__dropDown">
{countList.map((count) => {
return (
<p
key={count}
onClick={() => {
setOpenCountList(false);
setSelectedCount(count);
}}
>
{count}
</p> </p>
); );
})} })}
</div> </div>
)} )}
</div>
<div className="form__block__section">
<h3>Навыки</h3>
<div
className="form__block__skills"
onClick={() => {
setOpenSkillsSelect(true);
}}
>
{Boolean(selectedSkills.length) &&
selectedSkills.map((skill, index) => {
return (
<div className="skill" key={`selected-${skill.id}`}>
<span>{skill.name}</span>
<img
src={deleteIcon}
alt="delete"
onClick={() => {
setSkills((prevArray) => [...prevArray, skill]);
setFilteredSkills((prevArray) => [
...prevArray,
skill
]);
setSelectedSkills(
selectedSkills.filter((skill, indexSkill) => {
return indexSkill !== index;
})
);
}}
/>
</div>
);
})}
<input
type="text"
placeholder="Выберите навыки"
onChange={(e) => {
setFilteredSkills(
skills.filter((skill) => {
return skill.name
.toLowerCase()
.includes(e.target.value.toLowerCase());
})
);
}}
/>
</div> </div>
{openSkillsSelect && Boolean(filteredSkills.length) && (
<div className="form__block__dropDown">
{filteredSkills.map((skill, index) => {
return (
<span
key={skill.id}
onClick={() => {
setSelectedSkills((prevArray) => [
...prevArray,
skill
]);
setFilteredSkills(
filteredSkills.filter((skill, skillIndex) => {
return skillIndex !== index;
})
);
setSkills(
skills.filter((initSkill) => {
return initSkill.id !== skill.id;
})
);
setOpenSkillsSelect(false);
}}
>
{skill.name}
</span>
);
})}
</div>
)}
</div> </div>
</div> </div>
<div className="partner-add-request__form__block form__block"> <div className="partner-add-request__info">
<h3 className="form__block__title">Квалификация</h3> <div className="partner-add-request__info__block">
<div className="form__block__section"> <div className="partner-add-request__info__block__title">
<h3>Выберите уровень знаний </h3> <img src={processImg} alt="process" />
<div <h4>Процесс:</h4>
className="form__block__section__select"
onClick={() => setOpenLevelList(!openLevelList)}
>
<span>
{typeof selectedLevel === "string"
? selectedLevel
: selectedLevel.name}
</span>
<img
className={openLevelList ? "rotate" : ""}
src={arrowDown}
/>
</div> </div>
{openLevelList && Boolean(Object.values(levelList).length) && ( <p>
<div className="form__block__dropDown"> При аутстаффе мы предоставляем вам IT-специалистов при этом
{Object.values(levelList).map((level, index) => { они находятся в нашем штате.
return ( <br />
<p <br />
key={level} Вы сможете прособеседовать наших специалистов, посмотреть
onClick={() => { проекты и Git.
setOpenLevelList(false); </p>
setSelectedLevel({ name: level, id: index + 1 });
}}
>
{level}
</p>
);
})}
</div>
)}
</div> </div>
<div className="form__block__section"> <div className="partner-add-request__info__block">
<h3>Введите необходимое описание</h3> <div className="partner-add-request__info__block__title">
<textarea <img src={reportImg} alt="reportImg" />
value={inputs.description} <h4>Отчетность:</h4>
onChange={(e) =>
setInputs((prevValue) => ({
...prevValue,
description: e.target.value
}))
}
/>
</div>
<div className="form__block__section">
<h3>Необходимое количество человек на позицию</h3>
<div
className="form__block__section__select"
onClick={() => setOpenCountList(true)}
>
<span>{selectedCount}</span>
<img
className={openCountList ? "rotate" : ""}
src={arrowDown}
/>
</div> </div>
{openCountList && ( <p>
<div className="form__block__dropDown"> Вы можете обратиться к специалисту напрямую.
{countList.map((count) => { <br />
return ( <br />
<p Каждый день специалисты описывают выполненные работы и
key={count} затраченные на это часы.
onClick={() => { <br />
setOpenCountList(false); <br />
setSelectedCount(count); Можем выделить руководителя проекта и тестировщиков.
}} </p>
>
{count}
</p>
);
})}
</div>
)}
</div> </div>
<div className="form__block__buttons"> <div className="partner-add-request__info__block">
<Link to="/profile/requests" className="form__block__cancel"> <div className="partner-add-request__info__block__title">
Отмена <img src={documentsImg} alt="documentsImg" />
</Link> <h4>
<button Обмен <br />
onClick={() => handler()} документами:
className={ </h4>
disableBtn() </div>
? "form__block__save" <p>
: "form__block__save disable" В Личном кабинете платформы получайте отчеты выполненных работ
} и счеты на согласование и оплату
> </p>
Сохранить
</button>
</div> </div>
</div> </div>
</div> </div>
<div className="partner-add-request__info"> <div className="partner-add-request__special">
<div className="partner-add-request__info__block"> <h4>Основные требования по вакансии</h4>
<div className="partner-add-request__info__block__title"> <div className="form__block__section special__select">
<img src={processImg} alt="process" /> <h3>Локация</h3>
<h4>Процесс:</h4> <div
className="form__block__section__select"
onClick={() => setOpenLocationList(true)}
>
<span>{selectedLocation}</span>
<img
className={openLocationList ? "rotate" : ""}
src={arrowDown}
/>
</div> </div>
<p> {openLocationList && (
При аутстаффе мы предоставляем вам IT-специалистов при этом они <div className="form__block__dropDown">
находятся в нашем штате. {locationList.map((location, index) => {
<br /> return (
<br /> <p
Вы сможете прособеседовать наших специалистов, посмотреть key={index}
проекты и Git. onClick={() => {
</p> setOpenLocationList(false);
setSelectedLocation(location);
}}
>
{location}
</p>
);
})}
</div>
)}
</div> </div>
<div className="partner-add-request__info__block"> <div className="form__block__section">
<div className="partner-add-request__info__block__title"> <h3>Ставка</h3>
<img src={reportImg} alt="reportImg" /> <div className="form__block__section__input special__select">
<h4>Отчетность:</h4> <input type="text" placeholder="Оплата" />
</div> </div>
<p>
Вы можете обратиться к специалисту напрямую.
<br />
<br />
Каждый день специалисты описывают выполненные работы и
затраченные на это часы.
<br />
<br />
Можем выделить руководителя проекта и тестировщиков.
</p>
</div> </div>
<div className="partner-add-request__info__block"> <div className="form__block__buttons">
<div className="partner-add-request__info__block__title"> <Link to="/profile/requests" className="form__block__cancel">
<img src={documentsImg} alt="documentsImg" /> Отмена
<h4> </Link>
Обмен <br /> <button
документами: onClick={() => handler()}
</h4> className={
</div> disableBtn()
? "form__block__save"
: "form__block__save disable"
}
>
Сохранить
</button>
<p> <p>
В Личном кабинете платформы получайте отчеты выполненных работ и Нажимая "Сохранить", вы соглашаетесь с Правилами обработки и
счеты на согласование и оплату использования персональных данных
</p> </p>
</div> </div>
</div> </div>

View File

@ -23,6 +23,31 @@
line-height: 32px; line-height: 32px;
} }
&__main {
display: flex;
flex-direction: column;
row-gap: 30px;
}
&__special {
background: rgba(255, 255, 255, 1);
border-radius: 12px;
padding: 41px 45px 35px 55px;
display: flex;
flex-direction: column;
h4 {
font-weight: 700;
color: rgba(91, 104, 113, 1);
font-size: 20px;
line-height: 24px;
}
.special__select {
max-width: 450px;
}
}
&__section { &__section {
margin-top: 25px; margin-top: 25px;
display: flex; display: flex;
@ -99,6 +124,7 @@
font-size: 15px; font-size: 15px;
line-height: 18px; line-height: 18px;
outline: none; outline: none;
width: 100%;
} }
} }
@ -164,13 +190,23 @@
&__buttons { &__buttons {
display: flex; display: flex;
margin-top: 50px;
button { button {
max-width: 150px; max-width: 150px;
width: 100%; width: 100%;
height: 40px; height: 40px;
} }
p {
font-weight: 300;
font-size: 12px;
line-height: 18px;
color: rgba(0, 0, 0, 1);
margin-left: 50px;
max-width: 360px;
display: flex;
align-items: center;
}
} }
&__cancel { &__cancel {
@ -321,7 +357,7 @@
background: #ffffff; background: #ffffff;
border-radius: 12px; border-radius: 12px;
width: 100%; width: 100%;
padding: 74px 48px 136px 62px; padding: 74px 48px 67px 62px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
row-gap: 61px; row-gap: 61px;

View File

@ -1,7 +1,7 @@
import moment from "moment/moment"; import moment from "moment/moment";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Navigate, useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { getRequestDates, setRequestDate } from "@redux/reportSlice"; import { getRequestDates, setRequestDate } from "@redux/reportSlice";

View File

@ -44,9 +44,25 @@ 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(1);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const tabs = [
{
id: 1,
name: "Все"
},
{
id: 2,
name: "Фронтенд"
},
{
id: 3,
name: "Бэкенд"
}
];
const COLUMNS = [ const COLUMNS = [
{ {
label: "", label: "",
@ -256,6 +272,21 @@ export const PartnerCategories = () => {
<div className="partner-categories__items"> <div className="partner-categories__items">
{Boolean(initialNodes.length) ? ( {Boolean(initialNodes.length) ? (
<> <>
<div className="table__tabs">
{tabs.map((tab) => {
return (
<button
onClick={() => setActiveTab(tab.id)}
key={tab.id}
className={`table__tab ${
tab.id === activeTab ? "table__tab--active" : ""
}`}
>
{tab.name}
</button>
);
})}
</div>
<label className="table__search" htmlFor="search"> <label className="table__search" htmlFor="search">
Поиск по имени: Поиск по имени:
<input <input

View File

@ -204,6 +204,29 @@
} }
} }
&__tabs {
margin: 0 auto 36px 18px;
background: rgba(240, 242, 245, 1);
padding: 4px 8px 4px 8px;
border-radius: 6px;
display: flex;
}
&__tab {
color: rgba(46, 58, 89, 1);
font-size: 15px;
outline: none;
background: none;
border: none;
padding: 0 12px;
&--active {
background: rgba(255, 255, 255, 1);
border-radius: 5px;
font-size: 16px;
}
}
&__pagination { &__pagination {
width: 100%; width: 100%;
display: flex; display: flex;

View File

@ -11,7 +11,8 @@ 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 paymentIcon from "assets/icons/paymentIcon.png"; import financeIcon from "assets/icons/financeIcon.png";
import paymentIcon from "assets/icons/paymentIcon.png";
import settingIcon from "assets/icons/settingIcon.png"; import settingIcon from "assets/icons/settingIcon.png";
import summaryIcon from "assets/icons/summaryIcon.png"; import summaryIcon from "assets/icons/summaryIcon.png";
import timerIcon from "assets/icons/timerIcon.png"; import timerIcon from "assets/icons/timerIcon.png";
@ -28,10 +29,10 @@ export const Profile = () => {
const [profileItemsInfo] = useState({ const [profileItemsInfo] = useState({
developer: [ developer: [
{ {
path: "profile/calendar", path: "profile",
img: reportsIcon, img: paymentIcon,
title: "Ваша отчетность", title: "Работа в IT <br/>открытые запросы",
description: "<span></span>Отработанных в этом месяце часов" description: "Перейдите чтобы посмотреть <br/>открытые позиции"
}, },
{ {
path: "profile/summary", path: "profile/summary",
@ -42,20 +43,26 @@ export const Profile = () => {
{ {
path: "profile/tracker", path: "profile/tracker",
img: timerIcon, img: timerIcon,
title: "Трекер времени", title: "Трекер <br/>времени",
description: "Сколько времени занимает <br/>выполнение задач" description: "Сколько времени занимает <br/>выполнение задач"
}, },
// { {
// path: "profile/payouts", path: "profile/payouts",
// img: paymentIcon, img: financeIcon,
// title: "Выплаты", title: "Выплаты и <br/>финансы",
// description: "У вас <span>подтвержден</span> <br/>статус самозанятого" description: "У вас <span>подтвержден</span> <br/>статус самозанятого"
// }, },
{ {
path: "profile/settings", path: "profile/settings",
img: settingIcon, img: settingIcon,
title: "Настройки профиля", title: "Настройки <br/>профиля",
description: "Перейдите чтобы начать <br/>редактирование" description: "Перейдите чтобы начать <br/>редактирование"
},
{
path: "profile/calendar",
img: reportsIcon,
title: "Ваша <br/>отчетность",
description: "<span></span>Отработанных в этом месяце часов"
} }
], ],
partner: [ partner: [

View File

@ -3,11 +3,20 @@ import SVG from "react-inlinesvg";
import { AuthHeader } from "@components/Common/AuthHeader/AuthHeader"; import { AuthHeader } from "@components/Common/AuthHeader/AuthHeader";
import arrowReviewsLeft from "assets/icons/arrows/arrowReviewsLeft.png";
import arrowReviewsRight from "assets/icons/arrows/arrowReviewsRight.png";
import Ellipse from "assets/images/EllipseIntro.svg"; import Ellipse from "assets/images/EllipseIntro.svg";
import backgroundOpp from "assets/images/backgroundOpportunity.png"; import backgroundOpp from "assets/images/backgroundOpportunity.png";
import cat from "assets/images/cat.png"; import cat from "assets/images/cat.png";
import clue from "assets/images/clue.png"; import clue from "assets/images/clue.png";
import code1 from "assets/images/landingBackgroundCode1.png";
import code from "assets/images/landingBackgroundCode.png"; import code from "assets/images/landingBackgroundCode.png";
import reviewsImgMok from "assets/images/reviewsImgMok.png";
import flag from "assets/images/stackProjectsFlag.png";
import fly from "assets/images/stackProjectsFly.png";
import hand from "assets/images/stackProjectsHand.png";
import rabota from "assets/images/stackProjectsRabota.png";
import portfolio from "assets/images/stackSteptsPortfolio.png";
import "./stack.scss"; import "./stack.scss";
@ -43,6 +52,53 @@ export const Stack = () => {
] ]
} }
]; ];
const projects = [
{
description:
"Импортозамещение в управлении проектами <span>таск-трекер ITGuild</span>",
img: flag,
name: "flag"
},
{
description:
"<span>Работа Тудей</span> - это сервис, который специализируется на поиске работы на новых территориях Российской Федерации.",
img: rabota,
name: "rabota"
},
{
description:
"<span>Внедрение искусственного интеллекта</span> (ИИ) в IT-проекты. Интеграции любых популярных сервисов.",
img: hand,
name: hand
},
{
description:
"Новостной портал и удобный каталог компаний <span>DaInfo.pro</span> предоставляющих различные услуги и товары.",
img: fly,
name: "fly"
}
];
const steps = [
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>уточнение</span> деталей и <span>обсуждение</span> условий с менеджером ITGUILD"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>подписание договора</span> без обязательств оплаты на данном этапе"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>формирование</span> команды или подбор отдельных специалистов под требования клиентов"
},
{
miniInfo: "Окунитесь в экосистему ITGUIL",
info: "<span>интеграция специалистов</span> в команду клиента, ежедневная отчетность под контролем менеджера ITGUILD"
}
];
return ( return (
<section className="stack"> <section className="stack">
<AuthHeader /> <AuthHeader />
@ -128,6 +184,160 @@ export const Stack = () => {
</div> </div>
</div> </div>
</section> </section>
<section className="stack__projects projects">
<div className="stack__container projects__container">
<img className="projects__code" src={code} alt="code" />
<h3 className="projects__title">ITGUILD</h3>
<div className="projects__block">
<h4>Наши проекты</h4>
<div className="projects__examples">
{projects.map((project, index) => {
return (
<div key={index} className="stack__project">
<span className="project__img">
<img
className={project.name}
src={project.img}
alt="img"
/>
</span>
<p
dangerouslySetInnerHTML={{ __html: project.description }}
></p>
</div>
);
})}
</div>
<div className="projects__info">
<p>
<span>Мы обеспечиваем</span> финансовые, юридические и кадровые
гарантии, предоставляем SLA и берем на себя ответственность за
работу команды. Вам не требуется заниматься поиском, оформлением
или увольнением сотрудников {" "}
<span>мы берем на себя все хлопоты.</span>
</p>
<button>оставить заявку</button>
</div>
</div>
</div>
</section>
<section className="stack__steps">
<div className="stack__container steps__container">
<div className="steps__head">
<h4>как это работает?</h4>
<div className="steps__info">
<p>
Аутстаффинг представляет собой специфическую модель найма
персонала, отличающуюся от аутсорсинга.
</p>
<p>
<span>
В контексте аутстаффинга вы нанимаете специалистов в области
ИТ,
</span>{" "}
оплачивая их по их конкретным навыкам, и берете на себя
организацию их работы.
</p>
</div>
</div>
<div className="steps__items">
{steps.map((step, index) => {
return (
<div key={index} className="item__wrapper">
<div className="item__head">
<h4>{`${index + 1}.`}</h4>
<p>{step.miniInfo}</p>
</div>
<div className="steps__item" key={index}>
<p
className="item__info"
dangerouslySetInnerHTML={{ __html: step.info }}
/>
</div>
</div>
);
})}
</div>
<div className="steps__portfolio">
<img src={portfolio} alt="portfolio" />
</div>
<img
className="steps__code steps__code--first"
src={code}
alt="code"
/>
<img
className="steps__code steps__code--second"
src={code}
alt="code"
/>
</div>
<img src={backgroundOpp} className="steps__background" />
</section>
<section className="stack__reviews">
<div className="stack__container reviews__container">
<div className="reviews__info">
<div className="reviews__info-counter">375</div>
<span>Довольных клиентов</span>
<p>
Предоставляем на аутстаффинг frontend- и backend - разработчиков
уровня от junior до middle+
</p>
<p>
Можем сделать оценку проекта, ревью кода, составить коммерческое
предложение, рекомендации касаемо стека технологий и организации
архитектуры разрабатываемого проекта.
</p>
</div>
<div className="reviews__content">
<h4>Что о нас говорят</h4>
<div className="reviews__content-container">
<div className="review">
<div className="review__client">
<img src={reviewsImgMok} alt="reviewsImgMok" />
<span>Александр Гузеев</span>
<p>Руководитель проекта ООО ЭЛАР</p>
</div>
<div className="review__comment">
<p>
Команда ITGUILD берется за решение широкого круга задач, не
боясь при этом ни сжатых сроков, ни сложной специфики
проектов, и успешно доводит их ло решения. <br />
<br />
Разаработчики Кирилла смогли не только усилить существующую
команду разработки, став ее полноценной частью, но и
привести в проект новые идеи, свои знания и опыт.
</p>
</div>
</div>
<div className="reviews__content-buttons">
<button>
<img src={arrowReviewsLeft} alt="" />
</button>
<button>
<img src={arrowReviewsRight} alt="" />
</button>
</div>
</div>
</div>
<img
className="reviews__code reviews__code--first"
src={code1}
alt="code"
/>
<img
className="reviews__code reviews__code--second"
src={code1}
alt="code"
/>
</div>
</section>
<section className="stack__contact">
<div className="stack__container contact__container"></div>
</section>
</section> </section>
); );
}; };

View File

@ -9,7 +9,7 @@
display: flex; display: flex;
} }
&__intro { &__intro {
background: #EEEEEE; background: #eeeeee;
.intro { .intro {
&__container { &__container {
@ -32,7 +32,7 @@
&__title { &__title {
font-weight: 900; font-weight: 900;
color: #A7CA60; color: #a7ca60;
font-size: 88px; font-size: 88px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.03em; letter-spacing: 0.03em;
@ -44,12 +44,12 @@
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 39px; font-size: 39px;
font-weight: 700; font-weight: 700;
color: #4A4A4A; color: #4a4a4a;
} }
&__about { &__about {
max-width: 380px; max-width: 380px;
color: #4A4A4A; color: #4a4a4a;
font-size: 14px; font-size: 14px;
font-weight: 250; font-weight: 250;
margin-bottom: 34px; margin-bottom: 34px;
@ -68,14 +68,14 @@
&__link { &__link {
font-weight: 700; font-weight: 700;
font-size: 12px; font-size: 12px;
color: #A7CA60; color: #a7ca60;
} }
&__ellipse { &__ellipse {
z-index: 1; z-index: 1;
top: 45%; top: 45%;
left:50%; left: 50%;
transform:translate(-50%, -50%); transform: translate(-50%, -50%);
position: absolute; position: absolute;
} }
@ -96,7 +96,11 @@
position: absolute; position: absolute;
backdrop-filter: blur(8.699999809265137px); backdrop-filter: blur(8.699999809265137px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06); box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
background: linear-gradient(137deg, rgba(255, 255, 255, 0.34) 0%, rgba(206, 198, 198, 0.34) 100%); background: linear-gradient(
137deg,
rgba(255, 255, 255, 0.34) 0%,
rgba(206, 198, 198, 0.34) 100%
);
border-radius: 8px; border-radius: 8px;
top: -35px; top: -35px;
left: -25px; left: -25px;
@ -106,7 +110,7 @@
.aside { .aside {
&__logo { &__logo {
z-index: 2; z-index: 2;
font-family: 'Geraspoheko'; font-family: "Geraspoheko";
color: white; color: white;
font-size: 343px; font-size: 343px;
position: absolute; position: absolute;
@ -119,7 +123,11 @@
position: absolute; position: absolute;
backdrop-filter: blur(8.699999809265137px); backdrop-filter: blur(8.699999809265137px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.03); box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.03);
background: linear-gradient(137deg, rgba(255, 255, 255, 0.34) 0%, rgba(206, 198, 198, 0.34) 100%); background: linear-gradient(
137deg,
rgba(255, 255, 255, 0.34) 0%,
rgba(206, 198, 198, 0.34) 100%
);
border-radius: 8px; border-radius: 8px;
width: 182px; width: 182px;
height: 106px; height: 106px;
@ -129,7 +137,11 @@
display: flex; display: flex;
padding: 24px 20px 18px 30px; padding: 24px 20px 18px 30px;
border: 0.5px solid; border: 0.5px solid;
border-image-source: linear-gradient(137.79deg, #FFFFFF 9.15%, #F4F4F4 76.22%); border-image-source: linear-gradient(
137.79deg,
#ffffff 9.15%,
#f4f4f4 76.22%
);
p { p {
color: rgba(141, 141, 141, 1); color: rgba(141, 141, 141, 1);
@ -146,7 +158,7 @@
img { img {
position: absolute; position: absolute;
top: -25px; top: -25px;
left: 0 ; left: 0;
} }
&:before { &:before {
@ -176,16 +188,16 @@
&__button { &__button {
max-width: 200px; max-width: 200px;
width: 100%; width: 100%;
background: #A7CA60; background: #a7ca60;
font-size: 15px; font-size: 15px;
color: #4A4A4A; color: #4a4a4a;
padding: 14px 0; padding: 14px 0;
border-radius: 44px; border-radius: 44px;
border: none; border: none;
} }
&__opportunity { &__opportunity {
background: #1E1E1E; background: #1e1e1e;
position: relative; position: relative;
.background__opportunity--left { .background__opportunity--left {
@ -196,12 +208,11 @@
.background__opportunity--right { .background__opportunity--right {
position: absolute; position: absolute;
bottom: 0; bottom: -361px;
right: 0; right: 0;
} }
.opportunity { .opportunity {
&__container { &__container {
padding: 105px 0 0px; padding: 105px 0 0px;
flex-direction: column; flex-direction: column;
@ -223,7 +234,7 @@
display: flex; display: flex;
} }
&__title { &__title {
font-family: 'Geraspoheko'; font-family: "Geraspoheko";
font-weight: 400; font-weight: 400;
font-size: 343px; font-size: 343px;
line-height: 1.03; line-height: 1.03;
@ -231,7 +242,7 @@
z-index: 2; z-index: 2;
background: linear-gradient(360deg, #171717 0%, #2a2a2a 100%); background: linear-gradient(360deg, #171717 0%, #2a2a2a 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent -webkit-text-fill-color: transparent;
} }
&__info { &__info {
@ -267,7 +278,11 @@
border-radius: 8px; border-radius: 8px;
backdrop-filter: blur(8.699999809265137px); backdrop-filter: blur(8.699999809265137px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06); box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
background: linear-gradient(137deg, rgba(87, 87, 87, 0.34) 0%, rgba(104, 104, 104, 0.34) 100%); background: linear-gradient(
137deg,
rgba(87, 87, 87, 0.34) 0%,
rgba(104, 104, 104, 0.34) 100%
);
position: relative; position: relative;
border: 0.5px solid #717171; border: 0.5px solid #717171;
@ -301,6 +316,7 @@
flex-direction: column; flex-direction: column;
h4 { h4 {
text-transform: uppercase;
color: rgba(167, 202, 96, 1); color: rgba(167, 202, 96, 1);
letter-spacing: 0.03em; letter-spacing: 0.03em;
font-weight: 900; font-weight: 900;
@ -328,4 +344,487 @@
} }
} }
} }
&__projects {
background: rgba(238, 238, 238, 1);
.projects {
&__container {
padding-top: 190px;
padding-bottom: 81px;
}
&__code {
position: absolute;
left: -170px;
top: 24px;
}
&__title {
font-weight: 400;
font-size: 343px;
background: linear-gradient(to bottom, #ffffff, #dbdbdb);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-family: "Geraspoheko";
margin: 0 auto;
position: absolute;
width: 100%;
text-align: center;
top: -50px;
z-index: 2;
filter: drop-shadow(0px 0px 30px #00000021);
}
&__block {
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
z-index: 3;
h4 {
font-weight: 900;
font-size: 46px;
line-height: 98%;
letter-spacing: 0.03em;
text-transform: uppercase;
color: #4a4a4a;
}
}
&__examples {
display: flex;
margin-top: 98px;
justify-content: space-between;
width: 100%;
.stack__project {
display: flex;
flex-direction: column;
align-items: center;
row-gap: 35px;
.project__img {
border-radius: 8px;
width: 99px;
height: 81px;
background: #a7ca60;
position: relative;
img {
position: relative;
}
.flag {
bottom: 21px;
right: -10px;
}
.rabota {
top: -40px;
right: 25px;
}
.hand {
top: -45px;
left: -44px;
}
.fly {
top: -30px;
}
}
p {
font-weight: 250;
font-size: 14px;
line-height: 129%;
text-align: center;
color: #4a4a4a;
max-width: 226px;
span {
font-weight: 500;
}
}
}
}
&__info {
display: flex;
margin: 56px auto 0;
column-gap: 50px;
align-items: center;
border: 1px solid #f8f8f8;
border-radius: 8px;
padding: 47px 91px 47px 55px;
p {
max-width: 620px;
font-weight: 250;
font-size: 14px;
line-height: 129%;
color: #4a4a4a;
span {
font-weight: 500;
}
}
button {
padding: 15px 43px;
font-weight: 700;
font-size: 15px;
color: #4a4a4a;
background: #a7ca60;
border-radius: 44px;
border: none;
max-height: 46px;
width: 201px;
display: flex;
align-items: center;
}
}
}
}
&__steps {
background: rgb(30, 30, 30);
padding: 90px 0 40px;
position: relative;
.steps {
&__container {
flex-direction: column;
}
&__head {
display: flex;
justify-content: space-between;
width: 100%;
h4 {
font-weight: 900;
font-size: 66px;
line-height: 98%;
letter-spacing: 0.03em;
text-transform: uppercase;
color: #a7ca60;
max-width: 380px;
margin-bottom: 0;
}
}
&__info {
display: flex;
flex-direction: column;
row-gap: 20px;
max-width: 499px;
p {
font-weight: 300;
font-size: 15px;
line-height: 140%;
color: #bdbdbd;
}
span {
font-weight: 700;
}
}
&__items {
margin-top: 115px;
display: flex;
justify-content: space-between;
.item {
&__wrapper {
position: relative;
}
&__head {
position: absolute;
display: flex;
color: #a7ca60;
top: -45px;
left: 20px;
h4 {
margin-bottom: 0;
font-weight: 700;
font-size: 100px;
text-transform: uppercase;
line-height: 0.8;
}
p {
font-weight: 700;
font-size: 12px;
letter-spacing: 0.01em;
color: #a7ca60;
max-width: 114px;
}
}
}
}
&__item {
position: relative;
width: 235px;
height: 153px;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(3px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
background: linear-gradient(
137deg,
rgba(87, 87, 87, 0.34) 0%,
rgba(104, 104, 104, 0.34) 100%
);
border: 0.5px solid #717171;
border-radius: 8px;
.item {
&__info {
font-size: 15px;
line-height: 131%;
text-align: center;
color: #fff;
font-weight: 250;
max-width: 160px;
span {
font-weight: 700;
}
}
}
}
&__portfolio {
width: 100%;
position: absolute;
bottom: -40px;
display: flex;
img {
margin: 0 auto;
}
}
&__code {
position: absolute;
&--first {
top: -40px;
left: 70px;
}
&--second {
bottom: -40px;
right: 0;
}
}
}
.steps__background {
position: absolute;
right: 0;
top: -260px;
}
}
&__reviews {
background-color: #eeeeee;
.reviews {
&__container {
align-items: center;
column-gap: 58px;
padding-bottom: 48px;
}
&__code {
position: absolute;
mix-blend-mode: plus-lighter;
&--first {
top: 90px;
left: -180px;
}
&--second {
bottom: 0;
left: 400px;
}
}
&__info {
display: flex;
flex-direction: column;
align-items: flex-start;
background-color: #a7ca60;
border-radius: 24px 0 113px 0;
padding: 50px 22px 64px 44px;
max-width: 311px;
z-index: 1;
&::before {
content: "";
width: 182px;
height: 106px;
position: absolute;
backdrop-filter: blur(8.699999809265137px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
background: linear-gradient(
137deg,
rgba(255, 255, 255, 0.34) 0%,
rgba(206, 198, 198, 0.34) 100%
);
border-radius: 8px;
top: 62px;
left: 200px;
}
&::after {
content: "";
width: 182px;
height: 106px;
position: absolute;
backdrop-filter: blur(8.699999809265137px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
background: linear-gradient(
137deg,
rgba(255, 255, 255, 0.34) 0%,
rgba(206, 198, 198, 0.34) 100%
);
border-radius: 8px;
bottom: -30px;
left: -100px;
}
&-counter {
color: #ffffff;
font-weight: 900;
font-size: 124px;
line-height: 122px;
}
span {
color: #ffffff;
font-weight: 900;
font-size: 29px;
line-height: 31.61px;
text-transform: uppercase;
margin-bottom: 28px;
}
p {
color: #607536;
font-weight: 700;
font-size: 14px;
line-height: 17.22px;
&:last-child {
color: #ffffff;
font-weight: 300;
font-size: 14px;
margin-top: 37px;
}
}
}
&__content {
margin: 0 0 45px 0;
h4 {
text-transform: uppercase;
color: #4a4a4a;
font-weight: 900;
font-size: 46px;
line-height: 45.26px;
margin-bottom: 24px;
}
&-container {
display: flex;
flex-direction: row;
align-items: center;
column-gap: 20px;
.review {
display: grid;
grid-template-columns: 45% 55%;
align-items: center;
max-width: 517px;
padding: 35px;
border-radius: 8px;
border: 0.5px solid #ffffff;
background: linear-gradient(137deg, #ffffff -10%, #dddddd 100%);
box-shadow: inset;
&__client {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
color: #7e7e7e;
font-weight: 300;
font-size: 14px;
line-height: 16.24px;
margin-right: 48px;
img {
width: 88px;
height: 88px;
border-radius: 100px;
}
span {
color: #1e1e1e;
font-weight: 500;
font-size: 17px;
line-height: 19.72px;
margin: 18px 0 16px 0;
}
}
&__comment {
color: #4a4a4a;
font-weight: 250;
font-size: 14px;
line-height: 17px;
}
}
}
&-buttons {
display: flex;
flex-direction: column;
align-items: center;
button {
background-color: #ffffff;
width: 70px;
height: 64px;
border-radius: 5px;
border: none;
}
button:first-child {
margin-bottom: 22px;
}
}
}
}
}
&__contact {
background-color: #1e1e1e;
.contact {
&__container {
}
}
}
} }

View File

@ -33,9 +33,9 @@ export const Summary = () => {
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 [editSummeryOpen, setEditSummeryOpen] = useState(false); const [editSummaryOpen, setEditSummaryOpen] = useState(false);
const [editSkills, setEditSkills] = useState(false); const [editSkills, setEditSkills] = useState(false);
const [summery, setSummery] = 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([]);
@ -48,7 +48,7 @@ export const Summary = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
setSummery(profileInfo.vc_text); setSummary(profileInfo.vc_text);
setSelectedSkills(profileInfo.skillValues); setSelectedSkills(profileInfo.skillValues);
}, [profileInfo]); }, [profileInfo]);
@ -69,11 +69,11 @@ export const Summary = () => {
}).then(() => {}); }).then(() => {});
} }
function editSummery() { function editSummary() {
apiRequest("/resume/edit-text", { apiRequest("/resume/edit-text", {
method: "PUT", method: "PUT",
data: { data: {
resume: summery resume: summary
} }
}).then(() => { }).then(() => {
showNotification({ showNotification({
@ -221,21 +221,21 @@ export const Summary = () => {
<div className="summary__sections__head"> <div className="summary__sections__head">
<h3>Опыт работы</h3> <h3>Опыт работы</h3>
<button <button
className={editSummeryOpen ? "edit" : ""} className={editSummaryOpen ? "edit" : ""}
onClick={() => { onClick={() => {
if (editSummeryOpen) { if (editSummaryOpen) {
editSummery(); editSummary();
} }
setEditSummeryOpen(!editSummeryOpen); setEditSummaryOpen(!editSummaryOpen);
}} }}
> >
{editSummeryOpen ? "Сохранить" : "Редактировать"} {editSummaryOpen ? "Сохранить" : "Редактировать"}
</button> </button>
</div> </div>
{editSummeryOpen ? ( {editSummaryOpen ? (
<CKEditor <CKEditor
editor={ClassicEditor} editor={ClassicEditor}
data={summery} data={summary}
config={{ config={{
removePlugins: [ removePlugins: [
"CKFinderUploadAdapter", "CKFinderUploadAdapter",
@ -243,22 +243,19 @@ export const Summary = () => {
"EasyImage", "EasyImage",
"Image", "Image",
"ImageCaption", "ImageCaption",
"ImageStyle",
"ImageToolbar",
"ImageUpload", "ImageUpload",
"MediaEmbed", "MediaEmbed"
"BlockQuote"
] ]
}} }}
onChange={(event, editor) => { onChange={(event, editor) => {
const data = editor.getData(); const data = editor.getData();
setSummery(data); setSummary(data);
}} }}
/> />
) : ( ) : (
<div <div
className="experience__content" className="experience__content"
dangerouslySetInnerHTML={{ __html: summery }} dangerouslySetInnerHTML={{ __html: summary }}
></div> ></div>
)} )}
</div> </div>

View File

@ -64,13 +64,18 @@
&__back { &__back {
display: flex; display: flex;
align-items: center; align-items: center;
column-gap: 30px; column-gap: 10px;
margin-top: 20px; margin-top: 20px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
} }
img {
width: 23px;
}
p { p {
margin-bottom: 0; margin-bottom: 0;
font-weight: 400; font-weight: 400;