Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
Дмитрий Савенко 2023-02-27 14:08:09 +03:00
commit 760949f39a
29 changed files with 1380 additions and 297 deletions

View File

@ -19,6 +19,11 @@ import {ResultPage} from './pages/quiz/ResultPage'
import {Profile} from './pages/Profile/Profile.js' import {Profile} from './pages/Profile/Profile.js'
import {Summary} from './pages/Summary/Summary' import {Summary} from './pages/Summary/Summary'
import {ViewReport} from './pages/ViewReport/ViewReport' import {ViewReport} from './pages/ViewReport/ViewReport'
import {Tracker} from './pages/Tracker/Tracker'
import {Payouts} from './pages/Payouts/Payouts'
import {Settings} from './pages/Settings/Settings'
import {PartnerRequests} from './pages/PartnerRequests/PartnerRequests'
import {PartnerAddRequest} from './pages/PartnerAddRequest/PartnerAddRequest'
import './fonts/stylesheet.css' import './fonts/stylesheet.css'
import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap/dist/css/bootstrap.min.css'
@ -58,6 +63,11 @@ const App = () => {
<Route exact path='calendar' element={<ProfileCalendar/>}/> <Route exact path='calendar' element={<ProfileCalendar/>}/>
<Route exact path='summary' element={<Summary/>}/> <Route exact path='summary' element={<Summary/>}/>
<Route exact path='view' element={<ViewReport/>}/> <Route exact path='view' element={<ViewReport/>}/>
<Route exact path='tracker' element={<Tracker/>}/>
<Route exact path='payouts' element={<Payouts/>}/>
<Route exact path='settings' element={<Settings/>}/>
<Route exact path='requests' element={<PartnerRequests/>}/>
<Route exact path='add-request' element={<PartnerAddRequest/>}/>
</Route> </Route>
<Route path="*" element={<Navigate to="/" replace/>}/> <Route path="*" element={<Navigate to="/" replace/>}/>

View File

@ -95,6 +95,24 @@
box-shadow: 6px 5px 20px rgb(87 98 80 / 21%); box-shadow: 6px 5px 20px rgb(87 98 80 / 21%);
transform: scale(1.02); transform: scale(1.02);
} }
@media (max-width: 950px) {
width: 200px;
font-size: 15px;
height: 50px;
}
@media (max-width: 800px) {
width: auto;
height: auto;
padding: 15px;
white-space: nowrap;
}
@media (max-width: 590px) {
padding: 8px;
font-size: 12px;
}
} }
&__hours { &__hours {
@ -104,7 +122,8 @@
letter-spacing: normal; letter-spacing: normal;
line-height: 30px; line-height: 30px;
text-align: left; text-align: left;
margin-left: 68px; margin: 50px 0 0;
text-transform: capitalize;
span { span {
font-weight: 100; font-weight: 100;

View File

@ -6,7 +6,7 @@
padding-left: 68px; padding-left: 68px;
padding-right: 54px; padding-right: 54px;
padding-top: 48px; padding-top: 48px;
padding-bottom: 94px; padding-bottom: 40px;
font-family: 'LabGrotesque', sans-serif; font-family: 'LabGrotesque', sans-serif;
&__header { &__header {
@ -20,16 +20,27 @@
letter-spacing: normal; letter-spacing: normal;
line-height: 30px; line-height: 30px;
text-align: left; text-align: left;
@media (max-width: 500px) {
font-size: 1.7em;
}
} }
&-box { &-box {
display: flex; display: flex;
align-items: center; align-items: center;
margin-left: 40px; margin-left: 20px;
cursor: pointer;
img { img {
width: 6px; margin: 0px 10px;
height: 6px; width: 12px;
height: 12px;
&:first-child {
transform: rotate(180deg);
margin: 0;
}
} }
span { span {
@ -42,6 +53,10 @@
text-align: left; text-align: left;
margin-left: 10px; margin-left: 10px;
cursor: pointer; cursor: pointer;
@media (max-width: 500px) {
font-size: 1.2em;
}
} }
} }
} }
@ -79,8 +94,9 @@
button { button {
margin: 0 auto; margin: 0 auto;
width: 125px; //width: 125px;
height: 42px; //height: 42px;
padding: 0 5px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05); box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 5px; border-radius: 5px;
border: 1px solid #c4c4c4; border: 1px solid #c4c4c4;
@ -94,35 +110,67 @@
text-align: center; text-align: center;
a { a {
display: flex;
align-items: center;
justify-content: center;
width: 115px;
height: 42px;
text-decoration: none; text-decoration: none;
color: #000000; color: #000000;
img {
width: 16px;
height: 16px;
margin: 0 10px 0 0;
}
@media (max-width: 1200px) {
width: 90px;
height: 40px;
}
@media (max-width: 968px) {
width: 62px;
height: 40px;
font-size: 10px;
img {
margin-right: 2px;
}
}
@media (max-width: 610px) {
img {
display: none;
}
width: auto;
height: auto;
}
}
@media (max-width: 610px) {
width: 55px;
height: 45px;
}
@media (max-width: 480px) {
width: 45px;
height: 35px;
} }
} }
} }
} }
@media (max-width: 1200px) {
.calendar-component {
&__form {
button {
width: 100px;
height: 40px;
}
}
}
}
@media (max-width: 968px) { @media (max-width: 968px) {
.calendar-component { .calendar-component {
margin-bottom: 40px; margin-bottom: 40px;
padding: 28px 0 48px 0; padding: 28px 10px 48px 10px;
&__header { &__header {
h3 { //h3 {
position: absolute; // position: absolute;
top: -10%; // top: -10%;
left: 25%; // left: 25%;
} //}
&-box { &-box {
margin-left: 20px; margin-left: 20px;
@ -132,114 +180,103 @@
&__rectangle { &__rectangle {
margin: 24px 0; margin: 24px 0;
} }
&__form {
button {
width: 72px;
height: 40px;
img {
display: none;
}
}
}
} }
} }
@media (max-width: 768px) { //@media (max-width: 768px) {
.calendar-component__form > button { // .calendar-component__form > button {
width: 70px; // width: 70px;
height: 40px; // height: 40px;
//
// img {
// display: none;
// }
// }
//}
img { //@media (max-width: 540.98px) {
display: none; // .calendar-component__form > button {
} // width: 68px;
} // height: 40px;
} // }
//}
@media (max-width: 540.98px) { //
.calendar-component__form > button { //@media (max-width: 520.98px) {
width: 68px; // .calendar-component__form > button {
height: 40px; // width: 66px;
} // height: 40px;
} // }
//}
@media (max-width: 520.98px) { //
.calendar-component__form > button { //@media (max-width: 500.98px) {
width: 66px; // .calendar-component__form > button {
height: 40px; // width: 64px;
} // height: 40px;
} // }
//}
@media (max-width: 500.98px) { //
.calendar-component__form > button { //@media (max-width: 480.98px) {
width: 64px; // .calendar-component__form > button {
height: 40px; // width: 60px;
} // height: 40px;
} // }
//}
@media (max-width: 480.98px) { //
.calendar-component__form > button { //@media (max-width: 460.98px) {
width: 60px; // .calendar-component__form > button {
height: 40px; // width: 56px;
} // height: 40px;
} // }
//}
@media (max-width: 460.98px) { //
.calendar-component__form > button { //@media (max-width: 440.98px) {
width: 56px; // .calendar-component__form > button {
height: 40px; // width: 52px;
} // height: 40px;
} // }
//}
@media (max-width: 440.98px) { //
.calendar-component__form > button { //@media (max-width: 428.98px) {
width: 52px; // .calendar-component__form > button {
height: 40px; // width: 50px;
} // height: 40px;
} // }
//}
@media (max-width: 428.98px) { //
.calendar-component__form > button { //@media (max-width: 414.98px) {
width: 50px; // .calendar-component__form > button {
height: 40px; // width: 49px;
} // height: 40px;
} // }
//}
@media (max-width: 414.98px) { //
.calendar-component__form > button { //@media (max-width: 395.98px) {
width: 49px; // .calendar-component__form > button {
height: 40px; // width: 46px;
} // height: 40px;
} // }
//}
@media (max-width: 395.98px) { //
.calendar-component__form > button { //@media (max-width: 350.98px) {
width: 46px; // .calendar-component__form > button {
height: 40px; // width: 44px;
} // height: 40px;
} // }
//}
@media (max-width: 350.98px) { //
.calendar-component__form > button { //@media (max-width: 349.98px) {
width: 44px; // .calendar-component__form > button {
height: 40px; // width: 42px;
} // height: 40px;
} // }
//}
@media (max-width: 349.98px) { //
.calendar-component__form > button { //@media (max-width: 346.98px) {
width: 42px; // .calendar-component__form > button {
height: 40px; // width: 40px;
} // height: 40px;
} // }
//}
@media (max-width: 346.98px) {
.calendar-component__form > button {
width: 40px;
height: 40px;
}
}
.calendar__icon { .calendar__icon {
margin-right: 10px; margin-right: 10px;

View File

@ -30,6 +30,18 @@ export function getReports(value) {
return getReports; return getReports;
} }
export function getCreatedDate(day) {
if (day) {
return `${new Date(day).getFullYear()}-${new Date(day).getMonth() + 1}-${new Date(day).getDate()}`
} else {
const date = new Date();
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
return `${yyyy}-${mm}-${dd}`
}
}
export function currentMonth() { export function currentMonth() {
const currentMonth = moment().format('MMMM'); const currentMonth = moment().format('MMMM');
@ -40,6 +52,11 @@ export function currentMonthAndDay(day) {
return day.format('D MMMM'); return day.format('D MMMM');
} }
export function getCorrectDate(day) {
const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
return `${new Date(day).getDate()} ${months[new Date(day).getMonth()]} ${new Date(day).getFullYear()} года`
};
export function currentMonthAndDayReportPage() { export function currentMonthAndDayReportPage() {
return moment().format('D MMMM'); return moment().format('D MMMM');
} }

View File

@ -1,7 +1,7 @@
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 {currentMonth, getReports} from '../Calendar/calendarHelper' import {getReports} from '../Calendar/calendarHelper'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import moment from "moment"; import moment from "moment";
@ -14,23 +14,27 @@ import {urlForLocal} from "../../helper";
import {apiRequest} from "../../api/request"; import {apiRequest} from "../../api/request";
import { getProfileInfo } from '../../redux/outstaffingSlice' import { getProfileInfo } from '../../redux/outstaffingSlice'
import {setReportDate} from "../../redux/reportSlice"; import {getRequestDates, setReportDate, setRequestDate} from "../../redux/reportSlice";
import 'moment/locale/ru'
import './profileCalendar.scss' import './profileCalendar.scss'
export const ProfileCalendar = () => { export const ProfileCalendar = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const profileInfo = useSelector(getProfileInfo); const profileInfo = useSelector(getProfileInfo)
const [month, setMonth] = useState(''); const requestDates = useSelector(getRequestDates)
const [value, setValue] = useState(moment())
const [reports, setReports] = useState([]); const [reports, setReports] = useState([]);
const [totalHours, setTotalHours] = useState(0); const [totalHours, setTotalHours] = useState(0);
const [requestDates, setRequestDates] = useState(''); const [loader, setLoader] = useState(true)
const [loader, setLoader] = useState(false)
function setValueHandler (value) {
setValue(value)
}
useEffect(() => { useEffect(() => {
setRequestDates(getReports(moment())) dispatch(setRequestDate(getReports(moment())))
},[]); },[]);
useEffect( () => { useEffect( () => {
@ -54,10 +58,6 @@ export const ProfileCalendar = () => {
}) })
}, [requestDates]); }, [requestDates]);
useEffect(() => {
setMonth(currentMonth)
}, [month]);
return ( return (
<div className='profile__calendar'> <div className='profile__calendar'>
<ProfileHeader/> <ProfileHeader/>
@ -66,7 +66,7 @@ export const ProfileCalendar = () => {
<div className='summary__info'> <div className='summary__info'>
<div className='summary__person'> <div className='summary__person'>
<img src={urlForLocal(profileInfo.photo)} className='summary__avatar' alt='avatar'/> <img src={urlForLocal(profileInfo.photo)} className='summary__avatar' alt='avatar'/>
<p className='summary__name'>{profileInfo.fio} {profileInfo.specification}</p> <p className='summary__name'>{profileInfo.fio}, {profileInfo.specification} разработчик</p>
</div> </div>
<Link to='/report'> <Link to='/report'>
<button className="calendar__btn" onClick={() => { <button className="calendar__btn" onClick={() => {
@ -79,10 +79,7 @@ export const ProfileCalendar = () => {
: :
<div className='row'> <div className='row'>
<div className='col-12 col-xl-12'> <div className='col-12 col-xl-12'>
<ProfileCalendarComponent reportsDates={reports} /> <ProfileCalendarComponent setValueHandler={setValueHandler} value={value} reports={reports} totalHours={totalHours} />
<p className='calendar__hours'>
{month} : <span> {totalHours} часов </span>
</p>
</div> </div>
</div> </div>
} }

View File

@ -1,28 +1,29 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
// import ellipse from '../../images/ellipse.png' import arrow from '../../images/arrowCalendar.png'
import rectangle from '../../images/rectangle__calendar.png' import rectangle from '../../images/rectangle__calendar.png'
import calendarIcon from '../../images/calendar_icon.png' import calendarIcon from '../../images/calendar_icon.png'
import moment from 'moment' import moment from 'moment'
import 'moment/locale/ru' import {calendarHelper, currentMonth, currentMonthAndDay, getReports} from '../Calendar/calendarHelper'
import { calendarHelper, currentMonthAndDay} from '../Calendar/calendarHelper' import {setReportDate, setRequestDate} from '../../redux/reportSlice';
import { setReportDate } from '../../redux/reportSlice';
import {useDispatch} from "react-redux"; import {useDispatch} from "react-redux";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import 'moment/locale/ru'
import './../Calendar/calendarComponent.scss' import './../Calendar/calendarComponent.scss'
export const ProfileCalendarComponent = ({reportsDates}) => { export const ProfileCalendarComponent = React.memo(({value, setValueHandler, reports, totalHours}) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [value, setValue] = useState(moment()) const [currentDay] = useState(moment())
const [calendar, setCalendar] = useState([]) const [calendar, setCalendar] = useState([])
const [month, setMonth] = useState('');
useEffect(() => { useEffect(() => {
setCalendar(calendarHelper(value)) setCalendar(calendarHelper(value))
}, [value]) }, [value])
// function beforeToday(day) { useEffect(() => {
// return day.isBefore(new Date(), 'day') setMonth(value.format('MMMM'))
// } }, [month]);
function isToday(day) { function isToday(day) {
return day.isSame(new Date(), 'day') return day.isSame(new Date(), 'day')
@ -35,8 +36,8 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
} }
function dayStyles(day) { function dayStyles(day) {
if (value < day) return `block` if (currentDay < day) return `block`
for (const date of reportsDates) { for (const date of reports) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) { if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) {
return `before` return `before`
} }
@ -47,7 +48,7 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
} }
function correctRoute(day) { function correctRoute(day) {
for (const date of reportsDates) { for (const date of reports) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) { if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) {
return `../view` return `../view`
} }
@ -55,26 +56,40 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
return '../../report' return '../../report'
} }
// function prevMonth() { function prevMonth() {
// return value.clone().subtract(1, 'month') return value.clone().subtract(1, 'month')
// } }
//
// function nextMonth() { function nextMonth() {
// return value.clone().add(1, 'month'); return value.clone().add(1, 'month');
// } }
return ( return (
<div className='calendar-component'> <div className='calendar-component'>
<div className='calendar-component__header'> <div className='calendar-component__header'>
<h3>Мои отчеты</h3> <h3>Мои отчеты</h3>
{/*<div className='calendar-component__header-box'>*/} <div className='calendar-component__header-box' onClick={() => {
{/* <img src={ellipse} alt='' />*/} setValueHandler(prevMonth())
{/* <span onClick={() => setValue(prevMonth())}>{prevMonth().format('MMMM')}</span>*/} dispatch(setRequestDate(getReports(prevMonth())))
{/*</div>*/} }}>
{/*<div className='calendar-component__header-box'>*/} <img src={arrow} alt='' />
{/* <img src={ellipse} alt='' />*/} <span>
{/* <span onClick={() => setValue(nextMonth())}>{nextMonth().format('MMMM')}</span>*/} {prevMonth().format('MMMM')}
{/*</div>*/} </span>
</div>
<div className='calendar-component__header-box'>
<span>{value.format('YYYY')}</span>
</div>
<div className='calendar-component__header-box' onClick={() => {
setValueHandler(nextMonth())
dispatch(setRequestDate(getReports(nextMonth())))
}}>
<span>
{nextMonth().format('MMMM')}
</span>
<img src={arrow} alt='' />
</div>
</div> </div>
<div className='calendar-component__rectangle'> <div className='calendar-component__rectangle'>
@ -113,7 +128,10 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
)} )}
</div> </div>
</div> </div>
<p className='calendar__hours'>
{month} : <span> {totalHours} часов </span>
</p>
</div> </div>
) )
} })

View File

@ -15,6 +15,10 @@
.summary__info { .summary__info {
padding-right: 25px; padding-right: 25px;
@media (max-width: 500px) {
padding-right: 5px;
}
} }
.loader { .loader {
@ -49,4 +53,22 @@
transform: scale(1.02); transform: scale(1.02);
} }
} }
.summary__info {
@media (max-width: 800px) {
.summary__name {
margin: 0;
max-width: 220px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
@media (max-width: 500px) {
.summary__name {
max-width: 150px;
}
}
}
} }

View File

@ -21,6 +21,45 @@ export const ProfileHeader = () => {
const userRole = useSelector(getRole); const userRole = useSelector(getRole);
const profileInfo = useSelector(getProfileInfo); const profileInfo = useSelector(getProfileInfo);
const [user] = useState('developer')
const [navInfo] = useState({
developer: [
{
path: '/summary',
name: 'Резюме'
},
{
path: '/calendar',
name: 'Отчетность'
},
{
path: '/tracker',
name: 'Трекер'
},
{
path: '/payouts',
name: 'Выплаты'
},
{
path: '/settings',
name: 'Настройки'
},
],
partner: [
{
path: '/employees',
name: 'Сотрудники'
},
{
path: '',
name: 'Отчетность'
},
{
path: '/requests',
name: 'Запросы'
},
]
})
const [isLoggingOut, setIsLoggingOut] = useState(false); const [isLoggingOut, setIsLoggingOut] = useState(false);
@ -44,7 +83,14 @@ export const ProfileHeader = () => {
<header className='profileHeader'> <header className='profileHeader'>
<div className='profileHeader__head'> <div className='profileHeader__head'>
<div className='profileHeader__container'> <div className='profileHeader__container'>
<h2 className='profileHeader__title'>itguild.<span>для разработчиков</span></h2> <h2 className='profileHeader__title'>itguild.
<span>
{user === 'developer' ?
'для разработчиков' :
'для партнеров'
}
</span>
</h2>
<button onClick={handler} className='profileHeader__logout'> <button onClick={handler} className='profileHeader__logout'>
{isLoggingOut ? <Loader/> : 'Выйти'} {isLoggingOut ? <Loader/> : 'Выйти'}
</button> </button>
@ -53,16 +99,23 @@ export const ProfileHeader = () => {
<div className='profileHeader__info'> <div className='profileHeader__info'>
<div className='profileHeader__container'> <div className='profileHeader__container'>
<nav className='profileHeader__nav'> <nav className='profileHeader__nav'>
<NavLink end to={'/profile/summary'}>Резюме</NavLink> {
<NavLink end to={'/profile'}>Отчетность</NavLink> navInfo[user].map((link, index) => {
<NavLink end to={'/'}>Трекер</NavLink> return <NavLink key={index} end to={`/profile${link.path}`}>{link.name}</NavLink>
<NavLink end to={'/'}>Выплаты</NavLink> })
<NavLink end to={'/'}>Настройки</NavLink> }
</nav> </nav>
<div className='profileHeader__personalInfo'> <div className='profileHeader__personalInfo'>
<h3 className='profileHeader__personalInfoName'>{profileInfo?.fio}</h3> <h3 className='profileHeader__personalInfoName'>
<img src={profileInfo.photo ? urlForLocal(profileInfo.photo) : ""} className='profileHeader__personalInfoAvatar' alt='avatar'/> {user === 'developer' ?
profileInfo?.fio :
''
}
</h3>
<NavLink end to={'/profile'}>
<img src={profileInfo.photo ? urlForLocal(profileInfo.photo) : ""} className='profileHeader__personalInfoAvatar' alt='avatar'/>
</NavLink>
</div> </div>
</div> </div>
</div> </div>

View File

@ -71,6 +71,10 @@
font-size: 12px; font-size: 12px;
} }
} }
@media (max-width: 450px) {
column-gap: 8px;
}
} }
&__personalInfo { &__personalInfo {

View File

@ -2,6 +2,7 @@ import React, {useState, useEffect} from 'react'
import {useSelector} from 'react-redux' import {useSelector} from 'react-redux'
import {Link, useNavigate} from 'react-router-dom' import {Link, useNavigate} from 'react-router-dom'
import DatePicker, { registerLocale } from "react-datepicker" import DatePicker, { registerLocale } from "react-datepicker"
import {getCorrectDate, getCreatedDate} from '../Calendar/calendarHelper'
import ru from "date-fns/locale/ru" import ru from "date-fns/locale/ru"
registerLocale("ru", ru); registerLocale("ru", ru);
@ -27,18 +28,6 @@ const ReportForm = () => {
const navigate= useNavigate(); const navigate= useNavigate();
const reportDate = useSelector(getReportDate); const reportDate = useSelector(getReportDate);
const getCreatedDate = (day) => {
if (day) {
return `${new Date(day).getFullYear()}-${new Date(day).getMonth() + 1}-${new Date(day).getDate()}`
} else {
const date = new Date();
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
return `${yyyy}-${mm}-${dd}`
}
};
useEffect(() => { useEffect(() => {
initListeners() initListeners()
}, []) }, [])
@ -71,13 +60,11 @@ const ReportForm = () => {
const totalHours = inputs.reduce((a, b) => a + b.hours_spent, 0); const totalHours = inputs.reduce((a, b) => a + b.hours_spent, 0);
const deleteInput = (indexRemove) => { const deleteInput = (indexRemove) => {
if (indexRemove !== 0) { setInputs((prev) => prev.filter((el, index) => index !== indexRemove))
setInputs((prev) => prev.filter((el, index) => index !== indexRemove))
}
}; };
const handler = () => { const handler = () => {
if(!inputs[0].task) { if(!inputs[0].task || !inputs[0].hours_spent) {
setReportSuccess('Заполните задачи'); setReportSuccess('Заполните задачи');
setTimeout(() => setReportSuccess(''), 1000) setTimeout(() => setReportSuccess(''), 1000)
return return
@ -130,7 +117,7 @@ const ReportForm = () => {
src={calendarIcon} src={calendarIcon}
alt='' alt=''
/> />
{getCreatedDate(startDate)} {getCorrectDate(startDate)}
</div> </div>
<DatePicker <DatePicker
className='datePicker' className='datePicker'
@ -184,9 +171,11 @@ const ReportForm = () => {
: input : input
}))}/> }))}/>
</div> </div>
{index > 0 &&
<div className='report-form__task-remove'> <div className='report-form__task-remove'>
<img onClick={() => deleteInput(index)} src={remove} alt=''/> <img onClick={() => deleteInput(index)} src={remove} alt=''/>
</div> </div>
}
</form> </form>
) )
})} })}
@ -196,7 +185,6 @@ const ReportForm = () => {
<span>Добавить еще </span> <span>Добавить еще </span>
</div> </div>
</div> </div>
<div className='col-4'></div>
</div> </div>
<div className='row'> <div className='row'>

View File

@ -18,6 +18,10 @@
border-radius: 12px; border-radius: 12px;
margin: 25px 0 80px; margin: 25px 0 80px;
padding: 50px 40px; padding: 50px 40px;
@media (max-width: 555px) {
padding: 25px 20px;
}
} }
.report__head { .report__head {
@ -53,6 +57,10 @@
letter-spacing: normal; letter-spacing: normal;
line-height: 48.74px; line-height: 48.74px;
text-align: left; text-align: left;
@media (max-width: 555px) {
font-size: 2.5em;
}
} }
h3 { h3 {
@ -65,6 +73,11 @@
text-align: left; text-align: left;
margin-top: 52px; margin-top: 52px;
margin-bottom: 35px; margin-bottom: 35px;
@media (max-width: 555px) {
margin-top: 25px;
margin-bottom: 15px;
}
} }
} }
@ -84,6 +97,7 @@
letter-spacing: normal; letter-spacing: normal;
line-height: normal; line-height: normal;
text-align: left; text-align: left;
cursor: pointer;
img { img {
margin-left: 20px; margin-left: 20px;
@ -102,7 +116,7 @@
font-style: normal; font-style: normal;
letter-spacing: normal; letter-spacing: normal;
line-height: 48.74px; line-height: 48.74px;
width: 40px; width: 12px;
} }
&-list { &-list {
@ -144,16 +158,25 @@
line-height: normal; line-height: normal;
text-align: left; text-align: left;
margin-bottom: 26px; margin-bottom: 26px;
white-space: nowrap;
} }
} }
&-title { &-title {
&--description { //&--description {
margin-left: 20px; // margin-left: 20px;
} //}
&--hours { &--hours {
margin-left: 330px; margin-left: 330px;
@media (max-width: 810px) {
margin-left: 125px;
}
@media (max-width: 610px) {
margin-left: 25px;
}
} }
} }
@ -161,6 +184,10 @@
margin-left: 20px; margin-left: 20px;
display: flex; display: flex;
align-items: center; align-items: center;
img {
cursor: pointer;
}
} }
&-form { &-form {
@ -186,6 +213,14 @@
font-size: 1.8em; font-size: 1.8em;
padding-left: 20px; padding-left: 20px;
padding-right: 20px; padding-right: 20px;
@media (max-width: 810px) {
width: 250px;
}
@media (max-width: 610px) {
width: 150px;
}
} }
} }
@ -200,6 +235,18 @@
outline: none; outline: none;
font-size: 1.8em; font-size: 1.8em;
text-align: center; text-align: center;
@media (max-width: 500px) {
width: 100px;
}
@media (max-width: 440px) {
width: 75px;
}
@media (max-width: 410px) {
width: 50px;
}
} }
} }
} }
@ -235,6 +282,11 @@
padding-left: 20px; padding-left: 20px;
padding-right: 20px; padding-right: 20px;
outline: none; outline: none;
@media (max-width: 610px) {
max-width: 460px;
width: 100%;
}
} }
} }

View File

@ -3,7 +3,7 @@ export function createMarkup(text) {
} }
export function transformHtml(text) { export function transformHtml(text) {
let startHtml = {__html: text.split('<h2>').join('<br><h2>').split('<br>')}; let startHtml = {__html: text.split('<h3> || <h2>').join('<br><h2>').split('<br>')};
startHtml = startHtml.__html.filter((el) => startHtml = startHtml.__html.filter((el) =>
el !== null && el !== "" || el === 0 el !== null && el !== "" || el === 0
); );
@ -37,4 +37,4 @@ export const getToken = () => {
export const urlHasParams = (url) => url.indexOf('?') > 0 ? `${url}&${window.location.search.substr(1)}` : `${url}${window.location.search}`; export const urlHasParams = (url) => url.indexOf('?') > 0 ? `${url}&${window.location.search.substr(1)}` : `${url}${window.location.search}`;
export const urlForLocal = (url) => process.env.NODE_ENV === 'development' ? `https://itguild.info${url}` : url; export const urlForLocal = (url) => process.env.NODE_ENV === 'development' ? `https://itguild.info${url}` : url;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
src/images/arrowSelect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

BIN
src/images/selectArrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

View File

@ -0,0 +1,98 @@
import React from 'react';
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
import {Footer} from "../../components/Footer/Footer";
import arrowDown from "../../images/selectArrow.png"
import './partnerAddRequest.scss'
export const PartnerAddRequest = () => {
return (
<div className='partnerAddRequest'>
<ProfileHeader />
<div className='container'>
<h2 className='partnerAddRequest__title'>Страница добавления заявки</h2>
<div className='partnerAddRequest__section'>
<div className='partnerAddRequest__form'>
<div className='partnerAddRequest__form__block form__block'>
<h3 className='form__block__title'>Данные открытой позиции</h3>
<div className='form__block__section'>
<h3>Название вакансии</h3>
<div className='form__block__section__input'>
<input type='text' placeholder='Вакансия'/>
</div>
</div>
<div className='form__block__section'>
<h3>Выберите специализацию</h3>
<div className='form__block__section__selects'>
<div className='form__block__section__select'>
<span>Разработка</span>
<img src={arrowDown} />
</div>
<div className='form__block__section__select'>
<span>Backend Developer</span>
<img src={arrowDown} />
</div>
</div>
</div>
</div>
<div className='partnerAddRequest__form__block form__block'>
<h3 className='form__block__title'>Квалификация</h3>
<div className='form__block__section'>
<h3>Выберите уровень знаний </h3>
<div className='form__block__section__select'>
<span>Разработка</span>
<img src={arrowDown} />
</div>
</div>
<div className='form__block__section'>
<h3>Введите необходимое описание</h3>
<textarea/>
</div>
<div className='form__block__section'>
<h3>Необходимое количество человек на позицию</h3>
<div className='form__block__section__select'>
<span>2</span>
<img src={arrowDown} />
</div>
</div>
<div className='form__block__buttons'>
<button className='form__block__cancel'>Отмена</button>
<button className='form__block__save'>Сохранить</button>
</div>
</div>
</div>
<div className='partnerAddRequest__info'>
<div className='partnerAddRequest__info__block'>
<h4>Процесс:</h4>
<p>
При аутстафе мы предоставляем вам
it-специалистов при этом они находятся в
нашем штате.
<br/><br/>
Вы сможете прособеседовать наших
специалистов, посмотреть проекты и Git.
</p>
</div>
<div className='partnerAddRequest__info__block'>
<h4>Отчетность:</h4>
<p>
Вы можете обратиться к специалисту
напрямую.
<br/><br/>
Каждый день специалисты описывают
выполненные работы и затраченные
на это часы.
<br/><br/>
Можем выделить руководителя проекта
и тестировщиков.
</p>
</div>
</div>
</div>
</div>
<Footer />
</div>
)
}

View File

@ -0,0 +1,228 @@
.partnerAddRequest {
background: #F1F1F1;
height: 100%;
min-height: 100vh;
font-family: 'LabGrotesque', sans-serif;
.container {
max-width: 1160px;
margin-top: 23px;
@media (max-width: 570px) {
margin-top: 0;
}
}
&__title {
color: #000000;
font-weight: 700;
font-size: 22px;
line-height: 32px
}
&__section {
margin-top: 25px;
display: flex;
column-gap: 30px;
@media (max-width: 1020px) {
flex-direction: column;
row-gap: 22px;
}
}
&__form {
display: flex;
flex-direction: column;
row-gap: 22px;
@media (max-width: 1020px) {
order: 2;
}
}
.form__block {
background: #FFFFFF;
border-radius: 12px;
padding: 25px 95px 30px 55px;
min-width: 600px;
width: 100%;
@media (max-width: 750px) {
padding: 15px 50px 15px 30px;
min-width: auto;
}
&__title {
font-weight: 700;
font-size: 20px;
line-height: 24px;
color: #5B6871;
margin-bottom: 35px;
}
&__section {
margin-bottom: 35px;
&:last-child {
margin-bottom: 0;
}
h3 {
font-weight: 400;
font-size: 15px;
line-height: 18px;
color: #000000;
margin-bottom: 10px;
}
&__input {
background: #EFF2F7;
border-radius: 8px;
padding: 8px 12px;
margin-bottom: 35px;
@media (max-width: 1020px) {
max-width: 500px;
}
input {
background: none;
border: none;
color: #000000;
font-weight: 400;
font-size: 15px;
line-height: 18px;
outline: none;
}
}
&__selects {
display: flex;
column-gap: 32px;
justify-content: space-between;
@media (max-width: 1020px) {
justify-content: normal;
}
@media (max-width: 515px) {
flex-direction: column;
row-gap: 20px;
}
}
&__select {
padding: 8px 15px 9px 12px;
background: #EFF2F7;
border-radius: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
max-width: 202px;
width: 100%;
span {
color: #000000;
font-weight: 400;
font-size: 15px;
line-height: 18px;
}
}
textarea {
background: #EFF2F7;
border-radius: 8px;
width: 100%;
border: none;
height: 100px;
resize: none;
outline: none;
padding: 5px;
color: #000000;
font-weight: 400;
font-size: 15px;
line-height: 18px;
@media (max-width: 1020px) {
max-width: 500px;
}
}
}
&__buttons {
display: flex;
margin-top: 50px;
button {
max-width: 150px;
width: 100%;
height: 40px;
}
}
&__cancel {
border: 0.5px solid #8DC63F;
border-radius: 44px;
color: #6F6F6F;
font-weight: 400;
font-size: 14px;
line-height: 32px;
background: none;
margin-right: 23px;
}
&__save {
background: #52B709;
border-radius: 44px;
color: #FFFFFF;
font-weight: 700;
font-size: 14px;
line-height: 32px;
border: none;
}
}
footer {
margin-top: 70px;
}
&__info {
background: #FFFFFF;
border-radius: 12px;
width: 100%;
padding: 90px 48px 200px 62px;
display: flex;
flex-direction: column;
row-gap: 140px;
@media (max-width: 1020px) {
order: 1;
padding: 20px;
flex-direction: row;
column-gap: 50px;
}
@media (max-width: 500px) {
flex-direction: column;
row-gap: 20px;
}
&__block {
h4 {
color: #5B6871;
font-weight: 700;
font-size: 20px;
line-height: 24px;
}
p {
color: #000000;
font-weight: 400;
font-size: 15px;
line-height: 18px;
}
}
}
}

View File

@ -0,0 +1,64 @@
import React, {useState} from 'react';
import {Link} from "react-router-dom";
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
import {Footer} from "../../components/Footer/Footer";
import './partnerRequests.scss'
export const PartnerRequests = () => {
const [items] = useState([
{
name: 'PHP разработчик ',
count: 4
},
{
name: 'PHP разработчик ',
count: 4
},
{
name: 'PHP разработчик ',
count: 4
},
{
name: 'PHP разработчик ',
count: 4
}
])
return (
<div className='partnerRequests'>
<ProfileHeader />
<div className='container'>
<h2 className='partnerRequests__title'>Запросы</h2>
<div className='partnerRequests__section'>
<div className='partnerRequests__section__items'>
{
items.map((item, index) => {
return <Link key={index} to={''} className='partnerRequests__section__item'>
<p className='partnerRequests__section__item__name'>
{item.name}
</p>
<p className='partnerRequests__section__item__count'>
Подходящие кандидаты<span>{item.count}</span>
</p>
</Link>
})
}
</div>
<div className='partnerRequests__section__info'>
<h3>Инструкция: подачи заявки</h3>
<p>
Оператор компании заводит заявку и указывает необходимые параметры
количество сотрудников, стек, уровень специалиста
</p>
<Link to={'/profile/add-request'}>
<span>+</span>
Создать запрос
</Link>
</div>
</div>
</div>
<Footer/>
</div>
)
};

View File

@ -0,0 +1,199 @@
.partnerRequests {
background: #F1F1F1;
height: 100%;
min-height: 100vh;
font-family: 'LabGrotesque', sans-serif;
.container {
max-width: 1160px;
margin-top: 23px;
@media (max-width: 570px) {
margin-top: 0;
}
}
&__title {
color: #000000;
font-weight: 700;
font-size: 22px;
line-height: 32px;
}
&__section {
margin-top: 25px;
background: #FFFFFF;
border-radius: 12px;
padding: 33px 45px 40px;
display: flex;
column-gap: 30px;
@media (max-width: 795px) {
padding: 20px 25px 25px;
}
@media (max-width: 750px) {
flex-direction: column;
}
&__items {
display: flex;
width: 77%;
flex-wrap: wrap;
column-gap: 20px;
row-gap: 25px;
@media (max-width: 795px) {
row-gap: 10px;
column-gap: 15px;
}
@media (max-width: 750px) {
order: 2;
width: 100%;
}
}
&__item {
display: flex;
width: 48%;
flex-direction: column;
background: #F1F1F1;
border-radius: 12px;
padding: 20px 27px 15px 25px;
transition: 0.3s all ease;
position: relative;
max-height: 100px;
@media (max-width: 585px) {
width: 100%;
}
&:before {
content: '...';
position: absolute;
right: 27px;
bottom: 17%;
color: #6F6F6F;
font-size: 23px;
}
&:hover {
text-decoration: none;
box-shadow: 6px 5px 20px rgb(87 98 80 / 21%);
transform: scale(1.02);
}
&__name {
color: #111112;
font-weight: 700;
font-size: 16px;
line-height: 32px;
margin-bottom: 9px;
}
&__count {
color: #6F6F6F;
font-weight: 500;
font-size: 12px;
line-height: 24px;
display: flex;
margin-bottom: 0;
span {
color: #6F6F6F;
font-weight: 500;
font-size: 14px;
line-height: 24px;
background: #DDDDDD;
border-radius: 4px;
width: 21px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-left: 8px;
}
}
}
&__info {
display: flex;
flex-direction: column;
width: 22%;
padding-top: 5px;
@media (max-width: 750px) {
order: 1;
width: 100%;
text-align: center;
margin-bottom: 20px;
a {
margin: 0 auto;
width: 100%;
}
}
h3 {
color: #52B709;
font-weight: 700;
font-size: 14px;
line-height: 24px;
margin-bottom: 30px;
@media (max-width: 1085px) {
margin-bottom: 15px;
line-height: 18px;
}
}
p {
font-weight: 400;
font-size: 12px;
line-height: 24px;
color: #000000;
margin-bottom: 25px;
@media (max-width: 1085px) {
margin-bottom: 10px;
line-height: 19px;
}
}
a {
background: #52B709;
max-width: 150px;
border-radius: 44px;
height: 40px;
border: none;
font-weight: 400;
font-size: 12px;
line-height: 32px;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
transition: 0.3s all ease;
span {
color: white;
font-weight: 700;
font-size: 20px;
margin-right: 8px;
}
&:hover {
box-shadow: 6px 5px 20px rgb(87 98 80 / 21%);
transform: scale(1.02);
text-decoration: none;
color: #FFFFFF;
}
}
}
}
footer {
margin-top: 70px;
}
}

View File

@ -0,0 +1,11 @@
import React from 'react';
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
export const Payouts = () => {
return (
<div className='payouts'>
<ProfileHeader />
</div>
)
};

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, {useState} from 'react';
import {useSelector} from "react-redux"; import {useSelector} from "react-redux";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
@ -22,79 +22,114 @@ import './profile.scss'
export const Profile = () => { export const Profile = () => {
const profileInfo = useSelector(getProfileInfo); const profileInfo = useSelector(getProfileInfo);
const [user] = useState('developer')
const [profileItemsInfo] = useState({
developer: [
{
path: '/calendar',
img: reportsIcon,
title: 'Ваша отчетность',
description: '<span></span>Отработанных в этом месяце часов'
},
{
path: '/summary',
img: summaryIcon,
title: 'Данные и резюме',
description: 'Ваше резюме<br/><span>заполнено</span>'
},
{
path: '/tracker',
img: timerIcon,
title: 'Трекер времени',
description: 'Сколько времени занимает<br/> выполнение задач'
},
{
path: '/payouts',
img: paymentIcon,
title: 'Выплаты',
description: 'У вас <span>подтвержден</span><br/> статус самозанятого'
},
{
path: '/settings',
img: settingIcon,
title: 'Настройки аккаунта',
description: 'Перейдите чтобы начать<br/> редактирование'
}
],
partner: [
{
path: '/requests',
img: reportsIcon,
title: 'Запросы и открытые позиции',
description: '<span>У вас 2 вакансии<br/></span>открытые от лица компании'
},
{
path: '',
img: summaryIcon,
title: 'Данные персонала',
description: 'Наши специалисты <br/><span>уже работающие у вас</span>'
},
{
path: '/tracker',
img: timerIcon,
title: 'Трекер времени',
description: 'Контроль времени и<br/> выполнение задач'
},
{
path: '',
img: paymentIcon,
title: 'Договора и отчетность',
description: 'Ключевые условия<br/> договора'
},
{
path: '',
img: settingIcon,
title: 'Настройки аккаунта',
description: 'Перейдите чтобы начать<br/> редактирование'
}
]
})
return ( return (
<div className='profile'> <div className='profile'>
<ProfileHeader/> <ProfileHeader/>
<div className='container'> <div className='container'>
<h2 className='profile__title'>Добрый день, <span>{profileInfo.fio}</span></h2> <h2 className='profile__title'>
{user === 'developer' ?
<span><p>Добрый день,&nbsp;</p>{profileInfo.fio}</span>
:
'ООО НДВ Консалтинг'
}
</h2>
<div className='summary__info'> <div className='summary__info'>
<div className='summary__person'> <div className='summary__person'>
<img src={profileInfo.photo ? urlForLocal(profileInfo.photo) : ''} className='summary__avatar' alt='avatar'/> <img src={profileInfo.photo ? urlForLocal(profileInfo.photo) : ''} className='summary__avatar' alt='avatar'/>
<p className='summary__name'>{profileInfo.fio} {profileInfo.specification}</p> <p className='summary__name'>
{user === 'developer' ?
<span>{profileInfo.fio}, {profileInfo.specification} разработчик</span>
:
'ООО НДВ Консалтинг'
}
</p>
</div> </div>
</div> </div>
<div className='profile__items'> <div className='profile__items'>
<Link to={'/profile/calendar'} className='item'> {
<div className='item__about'> profileItemsInfo[user].map((item, index) => {
<img src={reportsIcon} alt='report'/> return <Link key={index} to={`/profile${item.path}`} className='item'>
<h3>Ваша отчетность</h3> <div className='item__about'>
</div> <img src={item.img} alt='itemImg'/>
<div className='item__info'> <h3>{item.title}</h3>
<p><span></span>Отработанных в этом месяце часов</p> </div>
<div className='item__infoLink'> <div className='item__info'>
<img src={rightArrow} alt='arrow'/> <p dangerouslySetInnerHTML={{__html: item.description}}></p>
</div> <div className='item__infoLink'>
</div> <img src={rightArrow} alt='arrow'/>
</Link> </div>
<Link to={'/profile/summary'} className='item'> </div>
<div className='item__about'> </Link>
<img src={summaryIcon} alt='summary'/> })
<h3>Данные и резюме</h3> }
</div>
<div className='item__info'>
<p>Ваше резюме<br/><span>заполнено</span></p>
<div className='item__infoLink'>
<img src={rightArrow} alt='arrow'/>
</div>
</div>
</Link>
<Link to={'/profile'} className='item'>
<div className='item__about'>
<img src={timerIcon} alt='timer'/>
<h3>Трекер времени</h3>
</div>
<div className='item__info'>
<p>Сколько времени занимает<br/> выполнение задач</p>
<div className='item__infoLink'>
<img src={rightArrow} alt='arrow'/>
</div>
</div>
</Link>
<Link to={'/profile'} className='item'>
<div className='item__about'>
<img src={paymentIcon} alt='payment'/>
<h3>Выплаты</h3>
</div>
<div className='item__info'>
<p>У вас <span>подтвержден</span><br/> статус самозанятого</p>
<div className='item__infoLink'>
<img src={rightArrow} alt='arrow'/>
</div>
</div>
</Link>
<Link to={'/profile'} className='item'>
<div className='item__about'>
<img src={settingIcon} alt='settings'/>
<h3>Настройки аккаунта</h3>
</div>
<div className='item__info'>
<p>Перейдите чтобы начать<br/> редактирование</p>
<div className='item__infoLink'>
<img src={rightArrow} alt='arrow'/>
</div>
</div>
</Link>
</div> </div>
</div> </div>
<Footer/> <Footer/>

View File

@ -10,6 +10,10 @@
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
span { span {
display: flex;
p {
color: black;
}
color: #52B709; color: #52B709;
} }
@ -17,6 +21,10 @@
font-size: 17px; font-size: 17px;
margin-top: 20px; margin-top: 20px;
} }
@media (max-width: 500px) {
font-size: 15px;
}
} }
&__info { &__info {
@ -63,6 +71,7 @@
@media (max-width: 925px) { @media (max-width: 925px) {
width: 100%; width: 100%;
padding: 15px 25px;
} }
&__about { &__about {
@ -71,6 +80,10 @@
align-items: center; align-items: center;
margin-bottom: 30px; margin-bottom: 30px;
@media (max-width: 925px) {
margin-bottom: 15px;
}
h3 { h3 {
color: #000000; color: #000000;
font-weight: 500; font-weight: 500;

View File

@ -0,0 +1,11 @@
import React from 'react';
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
export const Settings = () => {
return (
<div className='settings'>
<ProfileHeader />
</div>
)
};

View File

@ -31,10 +31,10 @@ export const Summary = () => {
<img src={arrow} alt='arrow'/> <img src={arrow} alt='arrow'/>
<p>Вернуться</p> <p>Вернуться</p>
</div>} </div>}
<div className='summary__info'> <div className={openGit ? 'summary__info openGit' : 'summary__info'}>
<div className='summary__person'> <div className='summary__person'>
<img src={urlForLocal(profileInfo.photo)} className='summary__avatar' alt='avatar'/> <img src={urlForLocal(profileInfo.photo)} className='summary__avatar' alt='avatar'/>
<p className='summary__name'>{profileInfo.fio} {profileInfo.specification}</p> <p className='summary__name'>{profileInfo.fio}, {profileInfo.specification} разработчик</p>
</div> </div>
{!openGit && {!openGit &&
<button className='summary__git' onClick={() => setOpenGit(true)}>Git</button> <button className='summary__git' onClick={() => setOpenGit(true)}>Git</button>
@ -57,7 +57,15 @@ export const Summary = () => {
</div> </div>
} }
{profileInfo.vc_text && !openGit && {profileInfo.vc_text && !openGit &&
<div className='summary__experience' dangerouslySetInnerHTML={transformHtml(profileInfo.vc_text)}> <div className='summary__experience'>
<div className='experience__block'>
<div className="summary__sections__head">
<h3>Описание опыта работы</h3>
<button>Редактировать раздел</button>
</div>
<div className="experience__content" dangerouslySetInnerHTML={{__html:profileInfo.vc_text}}>
</div>
</div>
</div> </div>
} }
{openGit && {openGit &&

View File

@ -55,13 +55,17 @@
justify-content: space-between; justify-content: space-between;
@media (max-width: 930px) { @media (max-width: 930px) {
padding: 0 40px; padding: 0 25px;
} }
@media (max-width: 690px) { @media (max-width: 690px) {
padding: 0 20px; padding: 0 20px;
min-height: 80px; min-height: 80px;
} }
@media (max-width: 500px) {
padding: 0 5px;
}
} }
&__person { &__person {
@ -69,9 +73,13 @@
align-items: center; align-items: center;
column-gap: 45px; column-gap: 45px;
@media (max-width: 690px) { @media (max-width: 825px) {
column-gap: 20px; column-gap: 20px;
} }
@media (max-width: 550px) {
column-gap: 10px;
}
} }
&__avatar { &__avatar {
@ -87,11 +95,29 @@
} }
} }
.openGit {
.summary__name {
max-width: none;
@media (max-width: 490px) {
max-width: 280px;
}
}
}
&__name { &__name {
font-weight: 500; font-weight: 500;
font-size: 16px; font-size: 16px;
line-height: 32px; line-height: 32px;
position: relative; position: relative;
white-space: nowrap;
//@media (max-width: 915px) {
// max-width: 220px;
// overflow: hidden;
// white-space: nowrap;
// text-overflow: ellipsis;
//}
@media (max-width: 690px) { @media (max-width: 690px) {
font-size: 14px; font-size: 14px;
@ -99,6 +125,18 @@
line-height: 15px; line-height: 15px;
} }
@media (max-width: 550px) {
max-width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0;
}
@media (max-width: 450px) {
max-width: 150px;
}
&:after { &:after {
content: ''; content: '';
position: absolute; position: absolute;
@ -240,6 +278,11 @@
line-height: 32px; line-height: 32px;
margin-bottom: 0; margin-bottom: 0;
} }
a:hover {
text-decoration: none;
color: #007bff;
}
} }
} }
} }

View File

@ -0,0 +1,11 @@
import React from 'react';
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
export const Tracker = () => {
return (
<div className='tacker'>
<ProfileHeader />
</div>
)
};

View File

@ -10,22 +10,12 @@ import {Footer} from "../../components/Footer/Footer";
import arrow from "../../images/right-arrow.png"; import arrow from "../../images/right-arrow.png";
import arrowSwitchDate from "../../images/arrowViewReport.png"; import arrowSwitchDate from "../../images/arrowViewReport.png";
import {apiRequest} from "../../api/request";
import {getCorrectDate, getCreatedDate} from '../../components/Calendar/calendarHelper'
import './viewReport.scss' import './viewReport.scss'
import {apiRequest} from "../../api/request";
export const ViewReport = () => { export const ViewReport = () => {
const getCreatedDate = (day) => {
if (day) {
return `${new Date(day).getFullYear()}-${new Date(day).getMonth() + 1}-${new Date(day).getDate()}`
} else {
const date = new Date();
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
return `${yyyy}-${mm}-${dd}`
}
};
const reportDate = useSelector(getReportDate); const reportDate = useSelector(getReportDate);
const [taskText, setTaskText] = useState([]); const [taskText, setTaskText] = useState([]);
@ -91,7 +81,7 @@ export const ViewReport = () => {
<img src={arrow} alt='arrow'/><p>Вернуться</p> <img src={arrow} alt='arrow'/><p>Вернуться</p>
</Link> </Link>
<div className='viewReport__bar'> <div className='viewReport__bar'>
<h3 className='viewReport__bar__date'>{getCreatedDate(reportDay)}</h3> <h3 className='viewReport__bar__date'>{getCorrectDate(reportDay)}</h3>
<p className='viewReport__bar__hours'>Вами потрачено на работу : <span>{totalHours} часов</span></p> <p className='viewReport__bar__hours'>Вами потрачено на работу : <span>{totalHours} часов</span></p>
{/*<div className='viewReport__bar__progressBar'>*/} {/*<div className='viewReport__bar__progressBar'>*/}
{/* <span></span>*/} {/* <span></span>*/}
@ -103,7 +93,7 @@ export const ViewReport = () => {
<div className='viewReport__switchDate__prev switchDate' onClick={() => previousDay()}> <div className='viewReport__switchDate__prev switchDate' onClick={() => previousDay()}>
<img src={arrowSwitchDate} alt='arrow'/> <img src={arrowSwitchDate} alt='arrow'/>
</div> </div>
<p>{getCreatedDate(reportDay)}</p> <p>{getCorrectDate(reportDay)}</p>
<div className={`viewReport__switchDate__next switchDate ${getCreatedDate(currentDay) === getCreatedDate(reportDay) ? 'disable' : ''}`} onClick={() => nextDay()}> <div className={`viewReport__switchDate__next switchDate ${getCreatedDate(currentDay) === getCreatedDate(reportDay) ? 'disable' : ''}`} onClick={() => nextDay()}>
<img src={arrowSwitchDate} alt='arrow'/> <img src={arrowSwitchDate} alt='arrow'/>
</div> </div>
@ -122,15 +112,15 @@ export const ViewReport = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{taskText.length && taskText.map((task) => { {taskText.length && taskText.map((task, index) => {
return <tr key={task.id}> return <tr key={task.id}>
<td> <td>
<p>{task.task}</p> <p>{index + 1}. {task.task}</p>
</td> </td>
<td> <td>
<div className='viewReport__done__hours__item'> <div className='viewReport__done__hours__item'>
<span>{task.hours}</span> <span>{task.hours}</span>
<p>часа на задачу</p> <p className='hours'>часов на задачу</p>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -27,6 +27,10 @@
span { span {
color: #52B709; color: #52B709;
} }
@media (max-width: 500px) {
font-size: 18px;
}
} }
&__back { &__back {
@ -60,11 +64,20 @@
height: 72px; height: 72px;
justify-content: space-between; justify-content: space-between;
@media (max-width: 500px) {
column-gap: 0;
justify-content: space-between;
}
&__date { &__date {
font-weight: 500; font-weight: 500;
font-size: 22px; font-size: 22px;
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
@media (max-width: 500px) {
font-size: 16px;
}
} }
&__hours { &__hours {
@ -73,6 +86,10 @@
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
@media (max-width: 500px) {
font-size: 11px;
}
span { span {
color: #52B709; color: #52B709;
font-weight: 700; font-weight: 700;
@ -120,6 +137,11 @@
column-gap: 140px; column-gap: 140px;
align-items: center; align-items: center;
@media (max-width: 500px) {
column-gap: 0;
justify-content: space-between;
}
p { p {
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
@ -164,6 +186,10 @@
margin: 0 -28px; margin: 0 -28px;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
@media (max-width: 1205px) {
margin: 0;
}
} }
&__done { &__done {
@ -171,6 +197,58 @@
border-collapse: separate; border-collapse: separate;
border-spacing: 28px 0; border-spacing: 28px 0;
@media (max-width: 1205px) {
display: grid;
border-collapse: collapse;
thead {
display: grid;
tr {
display: grid;
grid-template-columns: 74% calc(26% - 28px);
column-gap: 28px;
}
}
tbody {
display: grid;
tr {
display: grid;
grid-template-columns: 74% calc(26% - 28px);
column-gap: 28px;
}
}
}
@media (max-width: 900px) {
thead {
tr {
th {
padding: 15px;
}
}
}
tbody {
tr {
td {
padding: 15px;
display: flex;
justify-content: space-between;
}
}
}
}
@media (max-width: 650px) {
tr {
grid-template-columns: 74% calc(26% - 10px) !important;
column-gap: 10px !important;
}
}
th { th {
padding: 32px 40px; padding: 32px 40px;
background: white; background: white;
@ -179,6 +257,11 @@
font-size: 22px; font-size: 22px;
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
@media (max-width: 650px) {
font-size: 16px;
line-height: 20px;
}
} }
td { td {
@ -187,9 +270,15 @@
p { p {
font-weight: 400; font-weight: 400;
font-size: 12px; font-size: 15px;
line-height: 24px; line-height: 20px;
max-width: 755px;
color: #000000; color: #000000;
@media (max-width: 465px) {
text-align: center;
line-height: 14px;
}
} }
} }
@ -203,6 +292,15 @@
font-size: 17px; font-size: 17px;
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
@media (max-width: 750px) {
font-size: 14px;
line-height: 20px;
}
@media (max-width: 575px) {
text-align: center;
}
} }
} }
@ -228,8 +326,30 @@
align-items: center; align-items: center;
min-width: 155px; min-width: 155px;
.hours {
font-size: 15px;
@media (max-width: 1170px) {
font-size: 13px;
text-align: center;
}
}
@media (max-width: 900px) {
column-gap: 0;
justify-content: space-between;
min-width: auto;
width: 100%;
}
@media (max-width: 775px) {
flex-direction: column;
justify-content: center;
row-gap: 10px;
}
span { span {
width: 48px; max-width: 48px;
height: 48px; height: 48px;
background: #8DC63F; background: #8DC63F;
border-radius: 50px; border-radius: 50px;
@ -240,6 +360,13 @@
font-size: 22px; font-size: 22px;
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
width: 100%;
@media (max-width: 900px) {
max-width: 28px;
height: 28px;
font-size: 15px;
}
} }
p { p {
@ -266,16 +393,30 @@
margin: 25px 0; margin: 25px 0;
padding: 25px 35px; padding: 25px 35px;
@media (max-width: 650px) {
padding: 15px 20px;
}
h3 { h3 {
font-weight: 500; font-weight: 500;
font-size: 22px; font-size: 22px;
line-height: 32px; line-height: 32px;
@media (max-width: 650px) {
font-size: 16px;
line-height: 20px;
}
} }
p { p {
font-weight: 400; font-weight: 400;
font-size: 12px; font-size: 15px;
line-height: 24px; line-height: 20px;
@media (max-width: 650px) {
font-size: 10px;
line-height: 18px;
}
} }
} }
@ -295,6 +436,10 @@
line-height: 32px; line-height: 32px;
color: #000000; color: #000000;
@media (max-width: 500px) {
font-size: 18px;
}
span { span {
color: #8BCC60; color: #8BCC60;
font-weight: 500; font-weight: 500;
@ -304,5 +449,9 @@
footer { footer {
margin-top: 70px; margin-top: 70px;
@media (max-width: 575px) {
margin-top: 0;
}
} }
} }

View File

@ -2,7 +2,8 @@ import { createSlice } from '@reduxjs/toolkit';
const initialState = { const initialState = {
dateSelected: '', dateSelected: '',
reportDate: '' reportDate: '',
requestDates: ''
}; };
export const reportSlice = createSlice({ export const reportSlice = createSlice({
@ -15,13 +16,18 @@ export const reportSlice = createSlice({
setReportDate: (state, action) => { setReportDate: (state, action) => {
state.reportDate = action.payload; state.reportDate = action.payload;
}, },
setRequestDate: (state, action) => {
state.requestDates = action.payload
}
}, },
}); });
export const { dateSelected, setReportDate} = reportSlice.actions; export const { dateSelected, setReportDate, setRequestDate} = reportSlice.actions;
export const selectDate = (state) => state.report.dateSelected; export const selectDate = (state) => state.report.dateSelected;
export const getReportDate = (state) => state.report.reportDate; export const getReportDate = (state) => state.report.reportDate;
export const getRequestDates = (state) => state.report.requestDates
export default reportSlice.reducer; export default reportSlice.reducer;