diff --git a/config/paths.js b/config/paths.js index a11d1e69..56021c30 100644 --- a/config/paths.js +++ b/config/paths.js @@ -1,7 +1,7 @@ -const path = require('path'); +const path = require("path"); module.exports = { - public: path.resolve(__dirname, '../public'), - src: path.resolve(__dirname, '../src'), - build: path.resolve(__dirname, '../build'), - '@node_modules': path.resolve(__dirname, '../node_modules'), + public: path.resolve(__dirname, "../public"), + src: path.resolve(__dirname, "../src"), + build: path.resolve(__dirname, "../build"), + "@node_modules": path.resolve(__dirname, "../node_modules"), }; diff --git a/config/webpack/analyze.js b/config/webpack/analyze.js index 9718b610..3932d696 100644 --- a/config/webpack/analyze.js +++ b/config/webpack/analyze.js @@ -1,10 +1,10 @@ -const { merge } = require('webpack-merge'); +const { merge } = require("webpack-merge"); -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') - .BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = + require("webpack-bundle-analyzer").BundleAnalyzerPlugin; -const prod = require('./prod'); +const prod = require("./prod"); module.exports = merge(prod, { - plugins: [new BundleAnalyzerPlugin()] -}); \ No newline at end of file + plugins: [new BundleAnalyzerPlugin()], +}); diff --git a/config/webpack/dev.js b/config/webpack/dev.js index bd080cdf..e6f78bfb 100644 --- a/config/webpack/dev.js +++ b/config/webpack/dev.js @@ -1,14 +1,14 @@ -const paths = require('../paths'); +const paths = require("../paths"); -const webpack = require('webpack'); -const {merge} = require('webpack-merge'); +const webpack = require("webpack"); +const { merge } = require("webpack-merge"); -const common = require('./common'); +const common = require("./common"); module.exports = merge(common, { - target : 'web', - mode: 'development', - devtool: 'eval-cheap-source-map', + target: "web", + mode: "development", + devtool: "eval-cheap-source-map", devServer: { compress: true, @@ -17,7 +17,6 @@ module.exports = merge(common, { historyApiFallback: true, // open: true, port: 3000, - }, - plugins: [new webpack.HotModuleReplacementPlugin()] -}); \ No newline at end of file + plugins: [new webpack.HotModuleReplacementPlugin()], +}); diff --git a/config/webpack/prod.js b/config/webpack/prod.js index a08140ba..d40296dd 100644 --- a/config/webpack/prod.js +++ b/config/webpack/prod.js @@ -1,62 +1,59 @@ -const paths = require('../paths'); -const {merge} = require('webpack-merge'); -const common = require('./common'); - -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const paths = require("../paths"); +const { merge } = require("webpack-merge"); +const common = require("./common"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = merge(common, { - mode: 'production', - target :'browserslist', - entry: { - index: { - import: `${paths.src}/index.js`, - dependOn: ['react', 'helpers'] - }, - react: ['react', 'react-dom', 'prop-types'], - helpers: ['immer', 'nanoid'] + mode: "production", + target: "browserslist", + entry: { + index: { + import: `${paths.src}/index.js`, + dependOn: ["react", "helpers"], }, - devtool: false, - output: { - filename: 'js/[name].[hash:8].bundle.js', - publicPath: '/', - assetModuleFilename: '[hash][ext][query]' - }, - module: { - rules: [ - { - test: /\.(c|sa|sc)ss$/i, - use: [ - MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: {importLoaders: 1} - }, - 'postcss-loader', - 'sass-loader' - ] - }, - { - test: /\.(jpe?g|png|gif|svg)$/i, - type: 'asset/resource' - // type: 'asset' - }, - - ] - }, - plugins: [ - new MiniCssExtractPlugin({ - filename: '[name].[contenthash].css', - chunkFilename: '[id].css' - }), - + react: ["react", "react-dom", "prop-types"], + helpers: ["immer", "nanoid"], + }, + devtool: false, + output: { + filename: "js/[name].[hash:8].bundle.js", + publicPath: "/", + assetModuleFilename: "[hash][ext][query]", + }, + module: { + rules: [ + { + test: /\.(c|sa|sc)ss$/i, + use: [ + MiniCssExtractPlugin.loader, + { + loader: "css-loader", + options: { importLoaders: 1 }, + }, + "postcss-loader", + "sass-loader", + ], + }, + { + test: /\.(jpe?g|png|gif|svg|webp)$/i, + type: "asset/resource", + // type: 'asset' + }, ], - optimization: { - runtimeChunk: 'single' - }, - performance: { - hints: 'warning', - maxEntrypointSize: 512000, - maxAssetSize: 512000 - } -}); \ No newline at end of file + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: "[name].[contenthash].css", + chunkFilename: "[id].css", + }), + ], + optimization: { + runtimeChunk: "single", + }, + performance: { + hints: "warning", + maxEntrypointSize: 512000, + maxAssetSize: 512000, + }, +}); diff --git a/src/components/Achievement/Achievement.jsx b/src/components/Achievement/Achievement.jsx index 2e89f3d6..e9d4e32a 100644 --- a/src/components/Achievement/Achievement.jsx +++ b/src/components/Achievement/Achievement.jsx @@ -1,19 +1,19 @@ -import React from 'react' +import React from "react"; -import './achievement.scss' +import "./achievement.scss"; export const Achievement = ({ achievement }) => { return ( -
-
- achievement +
+
+ achievement
-
-
{achievement.title}
-
+
+
{achievement.title}
+
{achievement.description}
- ) -} + ); +}; diff --git a/src/components/Calendar/CalendarComponent.jsx b/src/components/Calendar/CalendarComponent.jsx index 1e6b3bc5..f3baeb88 100644 --- a/src/components/Calendar/CalendarComponent.jsx +++ b/src/components/Calendar/CalendarComponent.jsx @@ -3,7 +3,7 @@ import { calendarHelper, currentMonthAndDay } from "./calendarHelper"; import ellipse from "../../images/ellipse.png"; import rectangle from "../../images/rectangle__calendar.png"; -import calendarIcon from "../../images/calendar_icon.png"; +import calendarIcon from "../../images/calendar.svg"; import moment from "moment"; import "moment/locale/ru"; diff --git a/src/components/Candidate/Candidate.js b/src/components/Candidate/Candidate.jsx similarity index 99% rename from src/components/Candidate/Candidate.js rename to src/components/Candidate/Candidate.jsx index 2176f94b..8e52dbd2 100644 --- a/src/components/Candidate/Candidate.js +++ b/src/components/Candidate/Candidate.jsx @@ -18,7 +18,6 @@ import { apiRequest } from "../../api/request"; import { createMarkup } from "../../helper"; import gitImgItem from "../../images/gitItemImg.svg"; - import rectangle from "../../images/rectangle_secondPage.png"; import front from "../../images/front-end.webp"; import back from "../../images/back-end.webp"; diff --git a/src/components/CardControl/CardControl.js b/src/components/CardControl/CardControl.jsx similarity index 100% rename from src/components/CardControl/CardControl.js rename to src/components/CardControl/CardControl.jsx diff --git a/src/components/CardControl/CardControl.scss b/src/components/CardControl/CardControl.scss index df4d85a0..f7d68f91 100644 --- a/src/components/CardControl/CardControl.scss +++ b/src/components/CardControl/CardControl.scss @@ -1,73 +1,73 @@ -.control-card{ - max-width: 353px; - width: 100%; - padding: 35px 45px 15px 30px; - background: #FFFFFF; - border-radius: 12px; - text-decoration: none; - cursor: pointer; - transition: all 0.3s ease; +.control-card { + max-width: 353px; + width: 100%; + padding: 35px 45px 15px 30px; + background: #ffffff; + border-radius: 12px; + text-decoration: none; + cursor: pointer; + transition: all 0.3s ease; - &:hover { - box-shadow: 6px 5px 20px rgb(87 98 80 / 21%); - transform: scale(1.02); - } + &:hover { + box-shadow: 6px 5px 20px rgb(87 98 80 / 21%); + transform: scale(1.02); + } - @media (max-width: 1175px) { - width: 48%; - max-width: none; - } + @media (max-width: 1175px) { + width: 48%; + max-width: none; + } - @media (max-width: 925px) { - width: 100%; - padding: 15px 25px; - } + @media (max-width: 925px) { + width: 100%; + padding: 15px 25px; + } - &__about { - display: flex; - column-gap: 20px; - align-items: center; - margin-bottom: 30px; + &__about { + display: flex; + column-gap: 20px; + align-items: center; + margin-bottom: 30px; - @media (max-width: 925px) { - margin-bottom: 15px; - } + @media (max-width: 925px) { + margin-bottom: 15px; + } - h3 { - color: #000000; - font-weight: 500; - font-size: 18px; - line-height: 22px; - max-width: 125px; - margin-bottom: 0; - } - } + h3 { + color: #000000; + font-weight: 500; + font-size: 18px; + line-height: 22px; + max-width: 125px; + margin-bottom: 0; + } + } - &__info { - display: flex; - justify-content: space-between; - align-items: center; + &__info { + display: flex; + justify-content: space-between; + align-items: center; - p { - font-weight: 700; - font-size: 12px; - line-height: 20px; - color: #000000; - margin-bottom: 0; + p { + font-weight: 700; + font-size: 12px; + line-height: 20px; + color: #000000; + margin-bottom: 0; - span { - color: #52B709; - font-weight: 700; - } - } - &Link { - width: 48px; - height: 48px; - background: #DDEEC6; - border-radius: 50px; - display: flex; - justify-content: center; - align-items: center; - } - } - } \ No newline at end of file + span { + color: #52b709; + font-weight: 700; + } + } + &Link { + width: 48px; + height: 48px; + background: #ddeec6; + border-radius: 50px; + display: flex; + justify-content: center; + align-items: center; + } + } +} diff --git a/src/components/CategoriesItem/CategoriesItem.js b/src/components/CategoriesItem/CategoriesItem.jsx similarity index 100% rename from src/components/CategoriesItem/CategoriesItem.js rename to src/components/CategoriesItem/CategoriesItem.jsx diff --git a/src/components/CategoriesItem/categoriesItem.scss b/src/components/CategoriesItem/categoriesItem.scss index 55805cfd..eabcad44 100644 --- a/src/components/CategoriesItem/categoriesItem.scss +++ b/src/components/CategoriesItem/categoriesItem.scss @@ -2,7 +2,7 @@ display: flex; flex-direction: column; padding: 33px 32px 25px 28px; - background: #FFFFFF; + background: #ffffff; border-radius: 12px; transition: all 0.3s ease; position: relative; @@ -18,7 +18,6 @@ pointer-events: none; } - &__title { display: flex; align-items: center; @@ -43,7 +42,7 @@ p { max-width: 181px; margin-bottom: 0; - color: #6F6F6F; + color: #6f6f6f; font-weight: 400; font-size: 12px; line-height: 20px; @@ -55,7 +54,7 @@ justify-content: center; width: 48px; height: 48px; - background: #DDEEC6; + background: #ddeec6; border-radius: 50px; } } diff --git a/src/components/Description/Description.js b/src/components/Description/Description.jsx similarity index 97% rename from src/components/Description/Description.js rename to src/components/Description/Description.jsx index 031a07be..19e32042 100644 --- a/src/components/Description/Description.js +++ b/src/components/Description/Description.jsx @@ -9,9 +9,8 @@ import { selectProfiles } from "../../redux/outstaffingSlice"; import { urlForLocal } from "../../helper"; -import male from "../../images/medium_male.png"; import rectangle from "../../images/rectangle_secondPage.png"; -import cursorImg from "../../images/cursorImg.png"; +import cursorImg from "../../images/cursorImg.svg"; import "./description.scss"; diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js deleted file mode 100644 index 77347884..00000000 --- a/src/components/Footer/Footer.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react' - -import logo from '../../images/logoGuild.png' -import vk from '../../images/vkLogo.svg' -import tg from '../../images/tgFooter.png' -import email from '../../images/emailLogo.svg' - -import './footer.scss' - -export const Footer = () => { - return ( -
-
-
-
- logo -

Подберем и документально оформим IT-специалистов, после чего передадим исполнителей под ваше руководство. - Вы получаете полное управление над сотрудниками, имея возможность контролировать и заменять IT штат.

-
- © {new Date().getFullYear()} - Все права защищены -
-
-
-
- -

Войти в команду

-
- -
-
-
-
- ) -} diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx new file mode 100644 index 00000000..040abb8d --- /dev/null +++ b/src/components/Footer/Footer.jsx @@ -0,0 +1,53 @@ +import React from "react"; + +import logo from "../../images/logoGuild.png"; +import vk from "../../images/vkLogo.svg"; +import tg from "../../images/tgFooter.png"; +import email from "../../images/emailLogo.svg"; + +import "./footer.scss"; + +export const Footer = () => { + return ( +
+
+
+
+ logo +

+ Подберем и документально оформим IT-специалистов, после чего + передадим исполнителей под ваше руководство. Вы получаете полное + управление над сотрудниками, имея возможность контролировать и + заменять IT штат. +

+
+ © {new Date().getFullYear()} - Все права защищены +
+
+
+
+ +

Войти в команду

+
+ +
+
+
+
+ ); +}; diff --git a/src/components/Footer/footer.scss b/src/components/Footer/footer.scss index 59f2c49d..e129c7f7 100644 --- a/src/components/Footer/footer.scss +++ b/src/components/Footer/footer.scss @@ -4,7 +4,6 @@ footer { } .footer { - &__top { display: flex; align-items: start; @@ -21,7 +20,7 @@ footer { font-weight: 400; font-size: 12px; line-height: 16px; - color: #5B6871; + color: #5b6871; @media (max-width: 620px) { margin-left: 0; @@ -82,7 +81,7 @@ footer { font-weight: 400; font-size: 12px; line-height: 16px; - color: #5B6871; + color: #5b6871; } } @@ -90,7 +89,7 @@ footer { font-weight: 400; font-size: 10px; line-height: 16px; - color: #5B6871; + color: #5b6871; margin-left: 150px; @media (max-width: 720px) { @@ -98,7 +97,7 @@ footer { } &:hover { - color: #5B6871; + color: #5b6871; text-decoration: none; } } @@ -115,101 +114,4 @@ footer { margin-left: 0; } } - //margin-top: -3rem; - // - //&__left { - // display: flex; - // align-items: center; - //} - // - //&__description { - // padding: 0 100px 0 34px; - // - // span { - // color: #18586e; - // font-family: 'GT Eesti Pro Display'; - // font-size: 1.6em; - // font-weight: 400; - // font-style: normal; - // letter-spacing: normal; - // line-height: 16.81px; - // text-align: left; - // } - //} - // - //&__icon { - // text-align: end; - // - // img { - // margin-left: 20px; - // } - //} - // - //&__right { - // display: flex; - // flex-direction: column; - // align-items: left; - //} - // - //&__phone { - // color: #003b65; - // font-family: 'CeraPro'; - // font-size: 2.1em; - // letter-spacing: normal; - // line-height: 25px; - // text-align: left; - //} - // - //&__working-hours { - // color: #003b65; - // font-family: 'CeraPro'; - // font-size: 1.2em; - // font-weight: 400; - // font-style: normal; - // letter-spacing: normal; - // line-height: normal; - // margin-left: 24px; - //} - // - //&__copyright { - // padding: 1rem 1rem 1rem 5.6rem; - // font-family: 'Muller'; - // font-weight: 300; - // font-size: 1.2em; - //} } - -//@media (max-width: 1199px) { -// .footer { -// &__left { -// margin-bottom: 20px; -// } -// } -//} -// -//@media (max-width: 575.98px) { -// .footer { -// &__left { -// margin-top: 80px; -// } -// -// &__description { -// padding: 0; -// margin-left: 10px; -// -// span { -// font-size: 1.2em; -// } -// } -// -// &__icon { -// img { -// margin-left: 10px; -// } -// } -// -// &__right { -// margin-bottom: 20px; -// } -// } -//} diff --git a/src/components/Form/Form.js b/src/components/Form/Form.js deleted file mode 100644 index af4d5b11..00000000 --- a/src/components/Form/Form.js +++ /dev/null @@ -1,134 +0,0 @@ -import React, {useEffect, useState} from 'react' -import {useParams, useNavigate} from 'react-router-dom' -import {Loader} from '../Loader/Loader' -import PhoneInput from 'react-phone-input-2' -import 'react-phone-input-2/lib/style.css' -import './form.scss' - -import {apiRequest} from "../../api/request"; - -import Swal from 'sweetalert2' -import withReactContent from 'sweetalert2-react-content' - -const SweetAlert = withReactContent(Swal); - -const Form = () => { - - const navigate = useNavigate(); - - const urlParams = useParams(); - - const [status, setStatus] = useState(null); - const [data, setData] = useState({ - email: '', - phone: '', - comment: '' - }); - const [isFetching, setIsFetching] = useState(false); - - const handleModal = (status) => { - SweetAlert.fire({ - text: status !== 200 || 201 - ? 'Какие-то неполадки =(' - : 'Форма отправлена', - preConfirm: () => - status !== 200 || 201 ? () => { - setStatus(null) - } : () => { - setStatus(null); - navigate(`/candidate/${urlParams.id}`) - } - }); - }; - - useEffect(() => { - if (status) { - handleModal(status) - } - }, [status]); - - const handleChange = (e) => { - const {id, value} = e.target; - - setData((prev) => ({ - ...prev, - [id]: value - })) - }; - - const handleSubmit = (e) => { - e.preventDefault(); - - setIsFetching(true); - const formData = new FormData(); - formData.append('profile_id', urlParams.id); - formData.append('Email', data.email); - formData.append('phone', data.phone); - formData.append('comment', data.comment); - - apiRequest('/interview-request/create-interview-request', { - method: 'POST', - params: { - profile_id: urlParams.id, - ...data - } - }).then((res) => { - setStatus(res); - setIsFetching(false) - } - ) - }; - - return ( -
-
-
- - - - - - handleChange({target: {value: e, id: 'phone'}}) - } - /> - {/* */} - - - - - -
-
- ) -}; - -export default Form diff --git a/src/components/Form/Form.jsx b/src/components/Form/Form.jsx new file mode 100644 index 00000000..0c1c1231 --- /dev/null +++ b/src/components/Form/Form.jsx @@ -0,0 +1,125 @@ +import React, { useEffect, useState } from "react"; +import { useParams, useNavigate } from "react-router-dom"; +import PhoneInput from "react-phone-input-2"; + +import { apiRequest } from "../../api/request"; +import { Loader } from "../Loader/Loader"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; + +import "react-phone-input-2/lib/style.css"; +import "./form.scss"; + +const SweetAlert = withReactContent(Swal); + +const Form = () => { + const navigate = useNavigate(); + + const urlParams = useParams(); + + const [status, setStatus] = useState(null); + const [data, setData] = useState({ + email: "", + phone: "", + comment: "", + }); + const [isFetching, setIsFetching] = useState(false); + + const handleModal = (status) => { + SweetAlert.fire({ + text: + status !== 200 || 201 ? "Какие-то неполадки =(" : "Форма отправлена", + preConfirm: () => + status !== 200 || 201 + ? () => { + setStatus(null); + } + : () => { + setStatus(null); + navigate(`/candidate/${urlParams.id}`); + }, + }); + }; + + useEffect(() => { + if (status) { + handleModal(status); + } + }, [status]); + + const handleChange = (e) => { + const { id, value } = e.target; + + setData((prev) => ({ + ...prev, + [id]: value, + })); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + setIsFetching(true); + const formData = new FormData(); + formData.append("profile_id", urlParams.id); + formData.append("Email", data.email); + formData.append("phone", data.phone); + formData.append("comment", data.comment); + + apiRequest("/interview-request/create-interview-request", { + method: "POST", + params: { + profile_id: urlParams.id, + ...data, + }, + }).then((res) => { + setStatus(res); + setIsFetching(false); + }); + }; + + return ( +
+
+
+ + + + + + handleChange({ target: { value: e, id: "phone" } }) + } + /> + + + + + +
+
+ ); +}; + +export default Form; diff --git a/src/components/FrequentlyAskedQuestionsItem/FrequentlyAskedQuestionsItem.scss b/src/components/FrequentlyAskedQuestionsItem/FrequentlyAskedQuestionsItem.scss index 247dfe02..ac6ad084 100644 --- a/src/components/FrequentlyAskedQuestionsItem/FrequentlyAskedQuestionsItem.scss +++ b/src/components/FrequentlyAskedQuestionsItem/FrequentlyAskedQuestionsItem.scss @@ -7,23 +7,23 @@ margin: 0 0 -5px 29px; } - &__icon-question { - - } &__title { font-weight: 700; @include adaptiv-value("font-size", 28, 22, 1); line-height: 79%; color: #1458dd; } + &__body { position: relative; z-index: 2; display: block; + &:not(:last-child) { margin: 0 0 13px 0; } - p { + + p { word-break: break-word; background: #ffffff; border-radius: 12px; @@ -40,4 +40,4 @@ align-items: center; } } -} \ No newline at end of file +} diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js deleted file mode 100644 index 4616bf17..00000000 --- a/src/components/Header/Header.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import {LogoutButton} from "../LogoutButton/LogoutButton"; - -import './header.scss' - -export const Header = () => { - return ( -
-

- Аутстаффинг it-персонала -

- -
- ) -}; \ No newline at end of file diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx new file mode 100644 index 00000000..b8202c0a --- /dev/null +++ b/src/components/Header/Header.jsx @@ -0,0 +1,16 @@ +import React from "react"; + +import { LogoutButton } from "../LogoutButton/LogoutButton"; + +import "./header.scss"; + +export const Header = () => { + return ( +
+

+ Аутстаффинг it-персонала +

+ +
+ ); +}; diff --git a/src/components/Header/header.scss b/src/components/Header/header.scss index 423ca653..cb6cc2e3 100644 --- a/src/components/Header/header.scss +++ b/src/components/Header/header.scss @@ -9,7 +9,7 @@ flex: 1; text-align: center; color: #52b709; - font-family: 'GT Eesti Pro Display', sans-serif; + font-family: "GT Eesti Pro Display", sans-serif; font-size: 5em; font-weight: 700; font-style: normal; @@ -23,4 +23,4 @@ line-height: normal; } } -} \ No newline at end of file +} diff --git a/src/components/Loader/Loader.js b/src/components/Loader/Loader.js deleted file mode 100644 index b95eb504..00000000 --- a/src/components/Loader/Loader.js +++ /dev/null @@ -1,12 +0,0 @@ -import SVGLoader from 'react-loader-spinner' -import './loader.scss' -import React from "react"; - - -export const Loader = ({width = 50, height = 50, style}) => { - return ( -
- -
- ) -}; diff --git a/src/components/Loader/Loader.jsx b/src/components/Loader/Loader.jsx new file mode 100644 index 00000000..d61acb83 --- /dev/null +++ b/src/components/Loader/Loader.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import SVGLoader from "react-loader-spinner"; + +import "./loader.scss"; + +export const Loader = ({ width = 50, height = 50, style }) => { + return ( +
+ +
+ ); +}; diff --git a/src/components/Loader/loader.scss b/src/components/Loader/loader.scss index 8793f929..bfb8b104 100644 --- a/src/components/Loader/loader.scss +++ b/src/components/Loader/loader.scss @@ -5,6 +5,7 @@ justify-content: center; align-items: center; position: relative; + &:hover { path { fill: #6aaf5c; diff --git a/src/components/LogoutButton/LogoutButton.js b/src/components/LogoutButton/LogoutButton.js deleted file mode 100644 index 3f435b84..00000000 --- a/src/components/LogoutButton/LogoutButton.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, {useState} from 'react' -import {useNavigate} from 'react-router-dom' -import {useSelector} from 'react-redux' -import {useLogout} from "../../hooks/useLogout"; - -import {Loader} from '../Loader/Loader' - -import {getRole} from '../../redux/roleSlice' - -import './logoutButton.scss' - - -export const LogoutButton = () => { - const [isLoggingOut, setIsLoggingOut] = useState(false); - - const userRole = useSelector(getRole); - const navigate = useNavigate(); - const {logout} = useLogout(); - - return ( - - ) -}; diff --git a/src/components/LogoutButton/LogoutButton.jsx b/src/components/LogoutButton/LogoutButton.jsx new file mode 100644 index 00000000..7f52adf8 --- /dev/null +++ b/src/components/LogoutButton/LogoutButton.jsx @@ -0,0 +1,31 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useSelector } from "react-redux"; + +import { useLogout } from "../../hooks/useLogout"; +import { Loader } from "../Loader/Loader"; +import { getRole } from "../../redux/roleSlice"; + +import "./logoutButton.scss"; + +export const LogoutButton = () => { + const [isLoggingOut, setIsLoggingOut] = useState(false); + + const userRole = useSelector(getRole); + const navigate = useNavigate(); + const { logout } = useLogout(); + + return ( + + ); +}; diff --git a/src/components/LogoutButton/logoutButton.scss b/src/components/LogoutButton/logoutButton.scss index 3a615a66..3c793886 100644 --- a/src/components/LogoutButton/logoutButton.scss +++ b/src/components/LogoutButton/logoutButton.scss @@ -1,5 +1,4 @@ .logout-button { - position: relative; z-index: 100; display: flex; @@ -14,7 +13,7 @@ background-color: #6aaf5c; color: #ffffff; border: 3px solid #6aaf5c; - font-family: 'Muller', sans-serif; + font-family: "Muller", sans-serif; text-align: center; &:hover { diff --git a/src/components/Outstaffing/Outstaffing.js b/src/components/Outstaffing/Outstaffing.jsx similarity index 99% rename from src/components/Outstaffing/Outstaffing.js rename to src/components/Outstaffing/Outstaffing.jsx index aa812032..fd1fa6e8 100644 --- a/src/components/Outstaffing/Outstaffing.js +++ b/src/components/Outstaffing/Outstaffing.jsx @@ -3,7 +3,6 @@ import { useSelector, useDispatch } from "react-redux"; import OutstaffingBlock from "../OutstaffingBlock/OutstaffingBlock"; import TagSelect from "../Select/TagSelect"; - import { selectTags, getPositionId, diff --git a/src/components/OutstaffingBlock/OutstaffingBlock.js b/src/components/OutstaffingBlock/OutstaffingBlock.js deleted file mode 100644 index a171cd19..00000000 --- a/src/components/OutstaffingBlock/OutstaffingBlock.js +++ /dev/null @@ -1,118 +0,0 @@ -import React from 'react' -import OutsideClickHandler from 'react-outside-click-handler' -import {useDispatch, useSelector} from 'react-redux' -import { - selectItems, - selectedItems, - profiles, -} from '../../redux/outstaffingSlice' - -import {apiRequest} from "../../api/request"; - -import './outstaffingBlock.scss' - - -const handlePositionClick = ( - { - dispatch, - positionId, - isSelected, - onSelect, - apiRequest - }) => { - if (isSelected) { - apiRequest('/profile', { - params: { - limit: 1000 - }, - }).then((profileArr) => { - dispatch(profiles(profileArr)); - dispatch(selectedItems([])); - onSelect(positionId) - }) - } else { - apiRequest('/profile', { - params: { - limit: '1000', - position_id: positionId - }, - }).then((res) => { - dispatch(profiles(res)); - dispatch(selectedItems([])); - onSelect(positionId) - }) - } -}; - -const OutstaffingBlock = ( - { - dataTags = [], - selected, - img, - header, - positionId, - isSelected, - onSelect - }) => { - - - const dispatch = useDispatch(); - - const itemsArr = useSelector(selectItems); - - - const handleBlockClick = (item, id) => { - if (!itemsArr.find((el) => item === el.value)) { - dispatch(selectedItems([...itemsArr, {id, value: item, label: item}])) - } - }; - - let classes; - - dataTags.forEach((el) => { - if (el.name === 'skills_back') { - classes = 'back' - } else if (el.name === 'skills_design') { - classes = 'des' - } else if (el.name === 'skills_front') { - classes = 'front' - } - }); - - return ( - isSelected && onSelect(null)}> -
-
handlePositionClick( - { - dispatch, - positionId, - isSelected, - onSelect, - apiRequest - }) - }> -

{header}

- img -
-
-

# Популярный стек

- {dataTags && ( -
    - {dataTags.map((item) => ( -
  • handleBlockClick(item.value, item.id)} - > - {item.value} -
  • - ))} -
- )} -
-
-
- ) -}; - -export default OutstaffingBlock diff --git a/src/components/OutstaffingBlock/OutstaffingBlock.jsx b/src/components/OutstaffingBlock/OutstaffingBlock.jsx new file mode 100644 index 00000000..65ee2429 --- /dev/null +++ b/src/components/OutstaffingBlock/OutstaffingBlock.jsx @@ -0,0 +1,126 @@ +import React from "react"; +import OutsideClickHandler from "react-outside-click-handler"; +import { useDispatch, useSelector } from "react-redux"; +import { + selectItems, + selectedItems, + profiles, +} from "../../redux/outstaffingSlice"; + +import { apiRequest } from "../../api/request"; + +import "./outstaffingBlock.scss"; + +const handlePositionClick = ({ + dispatch, + positionId, + isSelected, + onSelect, + apiRequest, +}) => { + if (isSelected) { + apiRequest("/profile", { + params: { + limit: 1000, + }, + }).then((profileArr) => { + dispatch(profiles(profileArr)); + dispatch(selectedItems([])); + onSelect(positionId); + }); + } else { + apiRequest("/profile", { + params: { + limit: "1000", + position_id: positionId, + }, + }).then((res) => { + dispatch(profiles(res)); + dispatch(selectedItems([])); + onSelect(positionId); + }); + } +}; + +const OutstaffingBlock = ({ + dataTags = [], + selected, + img, + header, + positionId, + isSelected, + onSelect, +}) => { + const dispatch = useDispatch(); + + const itemsArr = useSelector(selectItems); + + const handleBlockClick = (item, id) => { + if (!itemsArr.find((el) => item === el.value)) { + dispatch(selectedItems([...itemsArr, { id, value: item, label: item }])); + } + }; + + let classes; + + dataTags.forEach((el) => { + if (el.name === "skills_back") { + classes = "back"; + } else if (el.name === "skills_design") { + classes = "des"; + } else if (el.name === "skills_front") { + classes = "front"; + } + }); + + return ( + isSelected && onSelect(null)}> +
+
+ handlePositionClick({ + dispatch, + positionId, + isSelected, + onSelect, + apiRequest, + }) + } + > +

{header}

+ img +
+
+

# Популярный стек

+ {dataTags && ( +
    + {dataTags.map((item) => ( +
  • handleBlockClick(item.value, item.id)} + > + {item.value} +
  • + ))} +
+ )} +
+
+
+ ); +}; + +export default OutstaffingBlock; diff --git a/src/components/OutstaffingBlock/outstaffingBlock.scss b/src/components/OutstaffingBlock/outstaffingBlock.scss index 40440084..074b85a4 100644 --- a/src/components/OutstaffingBlock/outstaffingBlock.scss +++ b/src/components/OutstaffingBlock/outstaffingBlock.scss @@ -1,15 +1,15 @@ body { - font-family: 'LabGrotesque', sans-serif !important; + font-family: "LabGrotesque", sans-serif !important; } .container { max-width: 1160px !important; } .catalog { - background: #F1F1F1; + background: #f1f1f1; height: 100%; min-height: 100vh; - font-family: 'LabGrotesque', sans-serif; + font-family: "LabGrotesque", sans-serif; padding-top: 23px; &__title { @@ -37,7 +37,7 @@ body { } & > p { - font-family: 'GT Eesti Pro Display'; + font-family: "GT Eesti Pro Display"; font-size: 1.2em; font-weight: 300; font-style: normal; @@ -60,7 +60,7 @@ body { right: 13%; top: 30%; max-width: 130px; - font-family: 'GT Eesti Pro Display'; + font-family: "GT Eesti Pro Display"; font-size: 18px; font-weight: 400; font-style: normal; @@ -85,7 +85,7 @@ body { &__items { li { - font-family: 'GT Eesti Pro Display'; + font-family: "GT Eesti Pro Display"; font-size: 1.8em; font-weight: 100; font-style: normal; diff --git a/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.js b/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.js deleted file mode 100644 index 7ef5f280..00000000 --- a/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import {Link} from "react-router-dom"; - -import './profileBreadcrumbs.scss' - -export const ProfileBreadcrumbs = ({ links }) => { - return ( -
- {links.map((link, index) => { - return {link.name} - }) - - } -
- ) -} diff --git a/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.jsx b/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.jsx new file mode 100644 index 00000000..1de2b38b --- /dev/null +++ b/src/components/ProfileBreadcrumbs/ProfileBreadcrumbs.jsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Link } from "react-router-dom"; + +import "./profileBreadcrumbs.scss"; + +export const ProfileBreadcrumbs = ({ links }) => { + return ( +
+ {links.map((link, index) => { + return ( + + {link.name} + + ); + })} +
+ ); +}; diff --git a/src/components/ProfileBreadcrumbs/profileBreadcrumbs.scss b/src/components/ProfileBreadcrumbs/profileBreadcrumbs.scss index 9992152d..ec39e890 100644 --- a/src/components/ProfileBreadcrumbs/profileBreadcrumbs.scss +++ b/src/components/ProfileBreadcrumbs/profileBreadcrumbs.scss @@ -7,7 +7,7 @@ } a { - color: #5B6871; + color: #5b6871; font-weight: 400; font-size: 12px; line-height: 16px; @@ -31,11 +31,11 @@ } &:after { - content: ''; + content: ""; background-image: url("../../images/BreadcrumbsArrow.png"); background-repeat: no-repeat; width: 7px; - height:10px; + height: 10px; position: absolute; right: -14px; } diff --git a/src/components/ProfileCalendar/ProfileCalendar.js b/src/components/ProfileCalendar/ProfileCalendar.jsx similarity index 95% rename from src/components/ProfileCalendar/ProfileCalendar.js rename to src/components/ProfileCalendar/ProfileCalendar.jsx index 67f3f9ee..39d71645 100644 --- a/src/components/ProfileCalendar/ProfileCalendar.js +++ b/src/components/ProfileCalendar/ProfileCalendar.jsx @@ -1,20 +1,16 @@ import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; +import { Link, Navigate } from "react-router-dom"; import { getReports } from "../Calendar/calendarHelper"; -import { Link, Navigate } from "react-router-dom"; import moment from "moment"; - import { ProfileCalendarComponent } from "./ProfileCalendarComponent"; import { Loader } from "../Loader/Loader"; import { ProfileHeader } from "../ProfileHeader/ProfileHeader"; -import { ProfileBreadcrumbs } from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs"; +import { ProfileBreadcrumbs } from "../ProfileBreadcrumbs/ProfileBreadcrumbs"; import { Footer } from "../Footer/Footer"; import { Navigation } from "../Navigation/Navigation"; -import { ViewReport } from "../../pages/ViewReport/ViewReport"; - import { urlForLocal } from "../../helper"; - import { apiRequest } from "../../api/request"; import { getProfileInfo } from "../../redux/outstaffingSlice"; import { diff --git a/src/components/ProfileCalendar/ProfileCalendarComponent.js b/src/components/ProfileCalendar/ProfileCalendarComponent.js index f3397f75..22468c77 100644 --- a/src/components/ProfileCalendar/ProfileCalendarComponent.js +++ b/src/components/ProfileCalendar/ProfileCalendarComponent.js @@ -1,23 +1,25 @@ import React, { useState, useEffect } from "react"; -import arrow from "../../images/arrowCalendar.png"; -import rectangle from "../../images/rectangle__calendar.png"; -import calendarIcon from "../../images/calendar_icon.png"; -import moment from "moment"; +import { useDispatch } from "react-redux"; +import { Link } from "react-router-dom"; + +import { + setReportDate, + setRequestDate, + setSendRequest, +} from "../../redux/reportSlice"; import { calendarHelper, currentMonthAndDay, getReports, hourOfNum, } from "../Calendar/calendarHelper"; -import { - setReportDate, - setRequestDate, - setSendRequest, -} from "../../redux/reportSlice"; -import { useDispatch } from "react-redux"; -import { Link } from "react-router-dom"; import ShortReport from "../ShortReport/ShortReport"; +import arrow from "../../images/arrowCalendar.png"; +import rectangle from "../../images/rectangle__calendar.png"; +import calendarIcon from "../../images/calendar.svg"; +import moment from "moment"; + import "moment/locale/ru"; import "./../Calendar/calendarComponent.scss"; diff --git a/src/components/ReportForm/ReportForm.js b/src/components/ReportForm/ReportForm.js index b1a5f3f8..31389b42 100644 --- a/src/components/ReportForm/ReportForm.js +++ b/src/components/ReportForm/ReportForm.js @@ -1,81 +1,100 @@ -import React, {useState, useEffect} from 'react' -import {useSelector} from 'react-redux' -import {Link, Navigate, useNavigate} from 'react-router-dom' -import DatePicker, { registerLocale } from "react-datepicker" -import {getCorrectDate, getCreatedDate, hourOfNum} from '../Calendar/calendarHelper' -import ru from "date-fns/locale/ru" +import React, { useState, useEffect } from "react"; +import { useSelector } from "react-redux"; +import { Link, Navigate, useNavigate } from "react-router-dom"; +import DatePicker, { registerLocale } from "react-datepicker"; +import { + getCorrectDate, + getCreatedDate, + hourOfNum, +} from "../Calendar/calendarHelper"; +import ru from "date-fns/locale/ru"; registerLocale("ru", ru); -import {Loader} from '../Loader/Loader' -import {Footer} from "../Footer/Footer"; -import {ProfileHeader} from "../ProfileHeader/ProfileHeader"; -import {ProfileBreadcrumbs} from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs" +import { Loader } from "../Loader/Loader"; +import { Footer } from "../Footer/Footer"; +import { ProfileHeader } from "../ProfileHeader/ProfileHeader"; +import { ProfileBreadcrumbs } from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs"; -import {apiRequest} from "../../api/request"; +import { apiRequest } from "../../api/request"; -import {getReportDate} from '../../redux/reportSlice' +import { getReportDate } from "../../redux/reportSlice"; -import calendarIcon from '../../images/calendar_icon.png' -import ellipse from '../../images/ellipse.png' -import remove from '../../images/remove.png' +import calendarIcon from "../../images/calendar.svg"; +import ellipse from "../../images/ellipse.png"; +import remove from "../../images/remove.png"; import arrow from "../../images/right-arrow.png"; -import './reportForm.scss' +import "./reportForm.scss"; import "react-datepicker/dist/react-datepicker.css"; -import { Navigation } from '../Navigation/Navigation' +import { Navigation } from "../Navigation/Navigation"; const ReportForm = () => { - if(localStorage.getItem('role_status') === '18') { - return + if (localStorage.getItem("role_status") === "18") { + return ; } - const navigate= useNavigate(); + const navigate = useNavigate(); const reportDate = useSelector(getReportDate); useEffect(() => { - initListeners() - }, []) + initListeners(); + }, []); const [isFetching, setIsFetching] = useState(false); - const [reportSuccess, setReportSuccess] = useState(''); - const [startDate, setStartDate] = useState(reportDate ? new Date (reportDate._d) : new Date()); + const [reportSuccess, setReportSuccess] = useState(""); + const [startDate, setStartDate] = useState( + reportDate ? new Date(reportDate._d) : new Date() + ); const [datePickerOpen, setDatePickerOpen] = useState(false); - const [inputs, setInputs] = useState([{task: '', hours_spent: '', minutes_spent: 0}]); - const [troublesInputValue, setTroublesInputValue] = useState(''); - const [scheduledInputValue, setScheduledInputValue] = useState(''); + const [inputs, setInputs] = useState([ + { task: "", hours_spent: "", minutes_spent: 0 }, + ]); + const [troublesInputValue, setTroublesInputValue] = useState(""); + const [scheduledInputValue, setScheduledInputValue] = useState(""); const addInput = () => { - setInputs((prev) => [...prev, {task: '', hours_spent: '', minutes_spent: 0}]) + setInputs((prev) => [ + ...prev, + { task: "", hours_spent: "", minutes_spent: 0 }, + ]); }; const initListeners = () => { - document.addEventListener('click', closeByClickingOut) - } + document.addEventListener("click", closeByClickingOut); + }; const closeByClickingOut = (event) => { - const path = event.path || (event.composedPath && event.composedPath()) + const path = event.path || (event.composedPath && event.composedPath()); - if (event && !path.find((div) => div.classList && (div.classList.contains('report-form__block-img') || div.classList.contains('react-datepicker-popper')))) { - setDatePickerOpen(false) + if ( + event && + !path.find( + (div) => + div.classList && + (div.classList.contains("report-form__block-img") || + div.classList.contains("react-datepicker-popper")) + ) + ) { + setDatePickerOpen(false); } - } + }; const totalHours = inputs.reduce((a, b) => a + b.hours_spent, 0); const deleteInput = (indexRemove) => { - setInputs((prev) => prev.filter((el, index) => index !== indexRemove)) + setInputs((prev) => prev.filter((el, index) => index !== indexRemove)); }; const handler = () => { for (let input of inputs) { - if(!input.task || !input.hours_spent) { - setReportSuccess('Заполните задачи'); - setTimeout(() => setReportSuccess(''), 2000) - return + if (!input.task || !input.hours_spent) { + setReportSuccess("Заполните задачи"); + setTimeout(() => setReportSuccess(""), 2000); + return; } } - apiRequest('/reports/create', { - method: 'POST', + apiRequest("/reports/create", { + method: "POST", data: { tasks: inputs, difficulties: troublesInputValue, @@ -84,156 +103,223 @@ const ReportForm = () => { status: 1, }, }).then((res) => { - setReportSuccess('Отчет отправлен'); + setReportSuccess("Отчет отправлен"); setTimeout(() => { - setReportSuccess('') - navigate('/profile/calendar'); - }, 1000) + setReportSuccess(""); + navigate("/profile/calendar"); + }, 1000); setInputs(() => []); - setTroublesInputValue(''); - setScheduledInputValue(''); + setTroublesInputValue(""); + setScheduledInputValue(""); setIsFetching(false); - setInputs(() => [{task: '', hours_spent: '', minutes_spent: 0}]); - }) + setInputs(() => [{ task: "", hours_spent: "", minutes_spent: 0 }]); + }); }; return ( -
- - -
- -

Ваши отчеты - добавить отчет

-
-
- -

Вернуться

- -
+
+ + +
+ +

+ Ваши отчеты - добавить отчет +

+
+
+ + +

Вернуться

+
+
-
-
-
-

Добавление отчета за день

-

Дата заполнения отчета:

-
-
setDatePickerOpen(true)}> - - {getCorrectDate(startDate)} -
- { - setDatePickerOpen(false) - setStartDate(date) - }} +
+
+
+

Добавление отчета за день

+

Дата заполнения отчета:

+
+
setDatePickerOpen(true)} + > + -
- - Какие задачи были выполнены? -
+ {getCorrectDate(startDate)}
+ { + setDatePickerOpen(false); + setStartDate(date); + }} + /> +
+ + Какие задачи были выполнены? +
+
-
-
-
-

- Краткое описание задачи -

-

Количество часов

-
+
+
+
+

+ Краткое описание задачи +

+

+ Количество часов +

+
- {inputs.map((input, index) => { - return ( -
-
- {index + 1}. -
-
- setInputs(inputs.map((input, inputIndex) => { - return index === inputIndex - ? { - ...input, - task: e.target.value - } - : input - }))}/> -
-
- setInputs(inputs.map((input, inputIndex) => { - return index === inputIndex - ? { - ...input, - hours_spent: Number(e.target.value) - } - : input - }))}/> -
- {index > 0 && -
- deleteInput(index)} src={remove} alt=''/> -
+ {inputs.map((input, index) => { + return ( + +
{index + 1}.
+
+ - ) - })} + name="text" + type="text" + onChange={(e) => + setInputs( + inputs.map((input, inputIndex) => { + return index === inputIndex + ? { + ...input, + task: e.target.value, + } + : input; + }) + ) + } + /> +
+
+ + setInputs( + inputs.map((input, inputIndex) => { + return index === inputIndex + ? { + ...input, + hours_spent: Number(e.target.value), + } + : input; + }) + ) + } + /> +
+ {index > 0 && ( +
+ deleteInput(index)} + src={remove} + alt="" + /> +
+ )} +
+ ); + })} -
-

+

- Добавить еще +
+

+ + +

+ Добавить еще +
+
+
+ +
+
+
+
+ + Какие сложности возникли?
+ setTroublesInputValue(e.target.value)} + /> +
+ + Что планируется сделать завтра? +
+ setScheduledInputValue(e.target.value)} + />
- -
-
-
-
- - Какие сложности возникли? +
+
+
+
+ +

+ Всего за день :{" "} + + {totalHours} {hourOfNum(totalHours)} + +

+ {reportSuccess && ( +

+ {reportSuccess} +

+ )}
- setTroublesInputValue(e.target.value)}/> -
- - Что планируется сделать завтра? -
- setScheduledInputValue(e.target.value)}/>
-
-
-
- -

- Всего за день : {totalHours} {hourOfNum(totalHours)} -

- {reportSuccess && -

{reportSuccess}

- } -
-
-
-
-
-
-
- ) +
+
+
+ ); }; -export default ReportForm +export default ReportForm; diff --git a/src/images/calendar_icon.png b/src/images/calendar_icon.png deleted file mode 100644 index 9d696927..00000000 Binary files a/src/images/calendar_icon.png and /dev/null differ diff --git a/src/images/cursorImg.png b/src/images/cursorImg.png deleted file mode 100644 index 51fa0832..00000000 Binary files a/src/images/cursorImg.png and /dev/null differ diff --git a/src/images/cursorImg.svg b/src/images/cursorImg.svg new file mode 100644 index 00000000..f65488b8 --- /dev/null +++ b/src/images/cursorImg.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/PartnerRequests/PartnerRequests.js b/src/pages/PartnerRequests/PartnerRequests.js index d41eb22e..d0c65b6d 100644 --- a/src/pages/PartnerRequests/PartnerRequests.js +++ b/src/pages/PartnerRequests/PartnerRequests.js @@ -14,7 +14,7 @@ import { Footer } from "../../components/Footer/Footer"; import { apiRequest } from "../../api/request"; -import cursorImg from "../../images/cursorImg.png"; +import cursorImg from "../../images/cursorImg.svg"; import "./partnerRequests.scss"; import { Navigation } from "../../components/Navigation/Navigation";