Просмотр исходного кода

Merge branch 'feature/patterns_fe' of Neca/HRCenter into FE_dev

pull/81/head
safet.purkovic 3 лет назад
Родитель
Сommit
180563d219
32 измененных файлов: 1715 добавлений и 27 удалений
  1. 26
    4
      src/AppRoutes.js
  2. Двоичные данные
      src/assets/images/send_message.png
  3. 627
    0
      src/assets/styles/components/_patterns.scss
  4. 7
    7
      src/components/MUI/NavbarComponent.js
  5. 53
    0
      src/components/Patterns/PatternCard.js
  6. 57
    0
      src/components/UI/CustomDrawer.js
  7. 42
    0
      src/components/UI/CustomModal.js
  8. 2
    0
      src/constants/pages.js
  9. 1
    0
      src/main.scss
  10. 18
    13
      src/pages/AdsPage/AdsPage.js
  11. 130
    0
      src/pages/PatternsPage/PatternDetailsPage.js
  12. 371
    0
      src/pages/PatternsPage/PatternsPage.js
  13. 8
    2
      src/request/apiEndpoints.js
  14. 14
    0
      src/request/patternsRequest.js
  15. 11
    0
      src/store/actions/createPattern/createPatternActionConstants.js
  16. 20
    0
      src/store/actions/createPattern/createPatternActions.js
  17. 11
    0
      src/store/actions/pattern/patternActionConstants.js
  18. 20
    0
      src/store/actions/pattern/patternActions.js
  19. 11
    0
      src/store/actions/patterns/patternsActionConstants.js
  20. 19
    0
      src/store/actions/patterns/patternsActions.js
  21. 11
    0
      src/store/actions/updatePattern/updatePatternActionConstants.js
  22. 20
    0
      src/store/actions/updatePattern/updatePatternActions.js
  23. 8
    0
      src/store/reducers/index.js
  24. 32
    0
      src/store/reducers/pattern/createPatternReducer.js
  25. 26
    0
      src/store/reducers/pattern/patternReducer.js
  26. 32
    0
      src/store/reducers/pattern/patternsReducer.js
  27. 32
    0
      src/store/reducers/pattern/updatePatternReducer.js
  28. 4
    0
      src/store/saga/adsSaga.js
  29. 3
    1
      src/store/saga/index.js
  30. 73
    0
      src/store/saga/patternsSaga.js
  31. 13
    0
      src/store/selectors/patternSelectors.js
  32. 13
    0
      src/store/selectors/patternsSelectors.js

+ 26
- 4
src/AppRoutes.js Просмотреть файл

@@ -17,6 +17,8 @@ import {
CANDIDATES_DETAILS_PAGE,
SELECTION_PROCESS_PAGE,
SELECTION_PROCESS_OF_APPLICANT_PAGE,
PATTERNS_PAGE,
PATTERN_DETAILS_PAGE,
SCHEDULE_PAGE,
STATS_PAGE
} from "./constants/pages";
@@ -34,12 +36,14 @@ import PrivateRoute from "./components/Router/PrivateRoute";
import ForgotPasswordConfirmationPage from "./pages/ForgotPasswordPage/ForgotPasswordConfirmationPageMUI";
import ResetPasswordPage from "./pages/ForgotPasswordPage/ResetPasswordPageMUI";
import UsersPage from "./pages/UsersPage/UsersPage";
import CandidatesPage from './pages/CandidatesPage/CandidatesPage'
import CandidatesPage from "./pages/CandidatesPage/CandidatesPage";
import AdDetailsPage from "./pages/AdsPage/AdDetailsPage";
import UserDetails from "./pages/UsersPage/UserDetails";
import CandidateDetailsPage from "./pages/CandidatesPage/CandidateDetailsPage";
import SelectionProcessPage from "./pages/SelectionProcessPage/SelectionProcessPage";
import SelectionProcessOfApplicantPage from "./pages/SelectionProcessPage/SelectionProcessOfApplicantPage";
import PatternsPage from "./pages/PatternsPage/PatternsPage";
import PatternDetailsPage from "./pages/PatternsPage/PatternDetailsPage";
import SchedulePage from "./pages/SchedulePage/SchedulePage";
import StatsPage from "./pages/StatsPage/StatsPage";

@@ -61,9 +65,27 @@ const AppRoutes = () => (
<PrivateRoute exact path={USER_DETAILS_PAGE} component={UserDetails} />
<PrivateRoute exact path={USERS_PAGE} component={UsersPage} />
<PrivateRoute exact path={CANDIDATES_PAGE} component={CandidatesPage} />
<PrivateRoute exact path={CANDIDATES_DETAILS_PAGE} component={CandidateDetailsPage} />
<PrivateRoute exact path={SELECTION_PROCESS_PAGE} component={SelectionProcessPage} />
<PrivateRoute exact path={SELECTION_PROCESS_OF_APPLICANT_PAGE} component={SelectionProcessOfApplicantPage} />
<PrivateRoute
exact
path={CANDIDATES_DETAILS_PAGE}
component={CandidateDetailsPage}
/>
<PrivateRoute
exact
path={SELECTION_PROCESS_PAGE}
component={SelectionProcessPage}
/>
<PrivateRoute
exact
path={SELECTION_PROCESS_OF_APPLICANT_PAGE}
component={SelectionProcessOfApplicantPage}
/>
<PrivateRoute
exact
path={PATTERN_DETAILS_PAGE}
component={PatternDetailsPage}
/>
<PrivateRoute exact path={PATTERNS_PAGE} component={PatternsPage} />
<PrivateRoute exact path={SCHEDULE_PAGE} component={SchedulePage} />
<PrivateRoute exact path={STATS_PAGE} component={StatsPage} />
<Redirect from="*" to={NOT_FOUND_PAGE} />

Двоичные данные
src/assets/images/send_message.png Просмотреть файл


+ 627
- 0
src/assets/styles/components/_patterns.scss Просмотреть файл

@@ -0,0 +1,627 @@
.patterns {
padding: 0 72px;
@include media-below($bp-xl) {
padding: 0 18px;
}
}

.patterns-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
padding-left: calc(144px - 72px);
margin-bottom: 18px !important;
@include media-below($bp-xl) {
padding-left: 18px;
}
}

.pattern-header-active-button {
background-color: $mainBlueLight !important;
}

.patterns-header button {
margin-left: 14px;
}

.patterns-cards {
padding: 0 calc(138px - 72px) 0 calc(144px - 72px);
display: flex;
flex-wrap: wrap;
width: 100% !important;
margin-bottom: 18px !important;
@include media-below($bp-xl) {
padding: 0 18px !important;
flex-direction: column !important;
}
}

.pattern-card-parent {
width: calc(100% / 3) !important;
margin-bottom: 36px;
padding-right: 36px;
@include media-below($bp-xl) {
width: 100% !important;
padding: 0 !important;
}
}

/* PATTERN CARD */
.pattern-card-with-icon {
position: relative;
}

.pattern-card {
position: relative;
box-sizing: border-box;
padding: 72px !important;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 18px;
isolation: isolate;
background: #ffffff;
border: 1px solid #e4e4e4;
border-radius: 18px;
width: 100% !important;
transition: 0.3s;
cursor: pointer;
}

.pattern-card:hover {
scale: 1.05;
border-color: $mainBlue !important;
background-color: $mainBlueLight !important;
}

.pattern-card-edit {
position: absolute;
top: 9px !important;
right: 9px !important;
border-radius: 50% !important;
width: 40px !important;
height: 40px !important;
z-index: 100;
}

.pattern-card-date p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 15px;
color: #272727;
flex: none;
order: 0;
flex-grow: 0;
z-index: 0;
}

.pattern-card-title p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 24px;
line-height: 32px;
letter-spacing: 0.02em;
color: $mainBlue;
flex: none;
order: 1;
flex-grow: 0;
z-index: 1;
}

.pattern-card-selection-proccess {
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 9px;
gap: 10px;
border: 1px solid #e4e4e4;
border-radius: 9px;
flex: none;
order: 2;
flex-grow: 0;
z-index: 2;
}

.pattern-card-date,
.pattern-card-title,
.pattern-card-selection-proccess {
display: flex !important;
justify-content: center !important;
}

.patterns-button {
padding-bottom: 18px;
display: flex;
justify-content: flex-end;
}

/* AD DETAILS */
.pattern-details {
padding: 42px 36px 72px 36px !important;
@include media-below($bp-xl) {
margin-top: 9px;
}
}

.pattern-details-header {
display: flex;
align-items: center;
justify-content: flex-end;
@include media-below($bp-xl) {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 14px;
justify-content: flex-start;
}
}

.pattern-details-header p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 20px;
text-align: right;
}

.pattern-details-header p span {
color: #9d9d9d;
}

.pattern-details-card {
margin: 41px auto 0 auto !important;
padding: 0 405px !important;
@include media-below($bp-xl) {
margin: 9px auto 0 auto !important;
padding: 0 !important;
}
}

.pattern-details-card-title {
display: flex;
align-items: center;
margin-bottom: 7px;
@include media-below($bp-xl) {
margin-top: 9px;
}
}

.pattern-details-card-title-title h1 {
font-size: 36px;
margin-right: 4px;
@include media-below($bp-xl) {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 18px;
line-height: 32px;
letter-spacing: 0.02em;
}
}

.pattern-details-card-title-sub {
font-size: 24px;
color: $mainBlue;
font-weight: 600;
@include media-below($bp-xl) {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 18px;
line-height: 32px;
letter-spacing: 0.02em;
}
}

.pattern-details-card-sub-card {
margin-bottom: 18px;
}

.pattern-details-card-sub-card-title {
margin-bottom: 10px;
}

.pattern-details-card-screening-title p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 20px;
color: #272727;
}

.pattern-details-card-sub-card-emails {
display: flex;
flex-wrap: wrap;
}

.pattern-details-card-sub-card-emails > div {
margin-right: 9px;
margin-bottom: 4px;
}

.pattern-details-card-sub-card-emails-email {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 9px;
gap: 10px;
background: #ffffff;
border: 1px solid #e4e4e4;
border-radius: 9px;
flex: none;
order: 0;
flex-grow: 0;
}

.pattern-details-card-sub-card-add-email {
display: flex;
}

.pattern-details-card-sub-card-add-email input {
margin-right: 18px;
flex: 50;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
padding: 18px;
gap: 10px;
background: #ffffff;
border: 1px solid #e4e4e4;
border-radius: 7px;
outline: none;
}

.pattern-details-card-sub-card-add-email button {
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 18px;
gap: 10px;
background: #ffffff;
border: 1px solid #226cb0;
border-radius: 9px;
flex: 1;
cursor: pointer;
transition: 0.3s;
}

.pattern-details-card-sub-card-add-email button:hover {
background-color: $mainBlueLight;
}

.pattern-details-card-sub-card-add-email button img {
width: 12px;
height: 12px;
}

.pattern-details-card-sub-card-message-pattern textarea {
resize: none;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: flex-start;
padding: 18px;
gap: 10px;
background: #f4f4f4;
border: 1px solid #e4e4e4;
border-radius: 7px;
min-height: 256px;
}

.pattern-details-card-buttons {
display: flex;
justify-content: flex-end;
align-items: center;
}

.pattern-details-card-buttons > * {
margin-left: 18px !important;
}

.custom-modal {
padding: 36px !important;
border: none !important;
border-radius: 18px;
}

.add-pattern-modal {
width: 512px;
min-height: 618px;
}

.add-pattern-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
}

.add-pattern-modal-header-title {
display: flex;
align-items: center;
}

.add-pattern-modal-header-title > * {
margin-right: 4px;
}

.add-pattern-modal-header-title-image img {
width: 18px;
height: 18px;
}

.add-pattern-modal-header-title-title p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 24px;
line-height: 32px;
letter-spacing: 0.02em;
color: #272727;
}

.add-pattern-modal-header-title-sub sub {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
line-height: 32px;
font-size: 18px;
letter-spacing: 0.02em;
color: $mainBlue;
}

.add-pattern-modal-header-close img {
width: 9px;
height: 10.5px;
cursor: pointer;
}

.add-pattern-modal-form-control {
display: flex;
flex-direction: column;
margin-bottom: 9px;
}

.add-pattern-modal-form-control label {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 20px;
color: #272727;
margin-bottom: 4.5px;
}

.add-pattern-modal-form-control input,
.add-pattern-modal-form-control select,
.add-pattern-modal-form-control textarea {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
padding: 18px;
gap: 10px;
border: 1px solid #e4e4e4;
border-radius: 7px;
outline: none;
}

.add-pattern-modal-form-control textarea {
resize: none;
}

.add-pattern-modal-form-control input[type="submit"] {
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 18px 72px;
gap: 10px;
background: #226cb0;
color: white;
border-radius: 9px;
cursor: pointer;
}

.edit-pattern-modal {
width: 512px;
min-height: 618px;
}

.edit-pattern-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
}

.edit-pattern-modal-header-title {
display: flex;
align-items: center;
}

.edit-pattern-modal-header-title > * {
margin-right: 4px;
}

.edit-pattern-modal-header-title-image img {
width: 18px;
height: 18px;
}

.edit-pattern-modal-header-title-title p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 24px;
line-height: 32px;
letter-spacing: 0.02em;
color: #272727;
}

.edit-pattern-modal-header-title-sub sub {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
line-height: 32px;
font-size: 18px;
letter-spacing: 0.02em;
color: $mainBlue;
}

.edit-pattern-modal-header-close img {
width: 9px;
height: 10.5px;
cursor: pointer;
}

.edit-pattern-modal-form-control {
display: flex;
flex-direction: column;
margin-bottom: 9px;
}

.edit-pattern-modal-form-control label {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 20px;
color: #272727;
margin-bottom: 4.5px;
}

.edit-pattern-modal-form-control input,
.edit-pattern-modal-form-control select,
.edit-pattern-modal-form-control textarea {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
padding: 18px;
gap: 10px;
border: 1px solid #e4e4e4;
border-radius: 7px;
outline: none;
}

.edit-pattern-modal-form-control textarea {
resize: none;
}

.edit-pattern-modal-form-control input[type="submit"] {
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 18px 72px;
gap: 10px;
background: #226cb0;
color: white;
border-radius: 9px;
cursor: pointer;
}

/* CUSTOM-FILTER-DRAWER */
.custom-drawer {
display: flex;
height: 100% !important;
flex-direction: column;
justify-content: space-between;
}

.custom-filter-drawer-header-container {
display: flex;
justify-content: space-between;
}

.custom-filter-drawer-header {
display: flex;
align-items: center;
}

.custom-filter-drawer-header-close {
cursor: pointer;
}

.custom-filter-drawer-header > * {
margin-right: 0.25rem;
}

.custom-filter-drawer-header img {
width: 18px;
height: 15.75px;
}

.custom-filter-drawer-header sub {
color: #226cb0;
}

.custom-filter-drawer-content {
margin-top: 18px !important;
box-sizing: border-box;
}

.custom-drawer-sub-card {
margin-bottom: 18px;
}

.custom-drawer-sub-card-label {
margin-bottom: 10px;
}

.custom-drawer-sub-card-label p {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 20px;
color: #272727;
}

.custom-drawer-sub-card-content-sub-label {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 20px;
color: #272727;
margin-bottom: 4.5px;
}

.custom-drawer-sub-card-content input[type="date"] {
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 18px;
gap: 10px;
border: 1px solid #e4e4e4;
border-radius: 9px;
}

.custom-drawer-submit {
margin-top: 18px;
padding-bottom: 18px;
}

.custom-drawer-submit > * {
width: 100%;
}

+ 7
- 7
src/components/MUI/NavbarComponent.js Просмотреть файл

@@ -56,7 +56,7 @@ const NavbarComponent = () => {
let btnRef = useRef();

// get authenticated user
const {user} = useSelector(s => s.user);
const { user } = useSelector((s) => s.user);

const { t } = useTranslation();

@@ -216,11 +216,11 @@ const NavbarComponent = () => {
display: "flex",
justifyContent: "center",
alignItems: "center",
width: matches ? '100%' : 'auto'
width: matches ? "100%" : "auto",
}}
>
{matches ? (
<Box
<Box
className="responsive-nav-cont"
style={{
display: "flex",
@@ -231,14 +231,14 @@ const NavbarComponent = () => {
<img
style={{ height: "37px", width: "37px", marginLeft: "0px" }}
src={HrLogo}
className='responsive-logo'
className="responsive-logo"
/>
<div
style={{
display: "flex",
alignItems: "center",
}}
className='icons-cont'
className="icons-cont"
>
<img src={searchIcon} />
<IconButton
@@ -296,7 +296,7 @@ const NavbarComponent = () => {
padding: "0",
textDecoration: "none",
}}
className={pathname === `/${n}` ? 'text-blue' : 'text-black'}
className={pathname === `/${n}` ? "text-blue" : "text-black"}
as={Link}
to={`/${n}`}
>
@@ -326,4 +326,4 @@ const NavbarComponent = () => {
);
};

export default NavbarComponent;
export default NavbarComponent;

+ 53
- 0
src/components/Patterns/PatternCard.js Просмотреть файл

@@ -0,0 +1,53 @@
import React from "react";
import PropTypes from "prop-types";
import editIcon from "../../assets/images/edit.png";
import { IconButton } from "@mui/material";

const PatternCard = ({
createdAt,
title,
selectionProcess,
isShownEdit,
onShowPatternDetails,
onOpenEditModal,
}) => {
return (
<div className="pattern-card-with-icon">
{isShownEdit && (
<div className="pattern-card-edit">
<IconButton
onClick={onOpenEditModal}
className={`c-btn--primary-outlined c-btn pattern-card-edit`}
>
<img
style={{ width: "16px !important", height: "16px !important" }}
src={editIcon}
/>
</IconButton>
</div>
)}
<div className="pattern-card" onClick={onShowPatternDetails}>
<div className="pattern-card-date">
<p>{new Date(createdAt).toLocaleDateString()}</p>
</div>
<div className="pattern-card-title">
<p>{title}</p>
</div>
<div className="pattern-card-selection-proccess">
<p>{selectionProcess}</p>
</div>
</div>
</div>
);
};

PatternCard.propTypes = {
createdAt: PropTypes.any,
title: PropTypes.string,
selectionProcess: PropTypes.string,
isShownEdit: PropTypes.bool,
onShowPatternDetails: PropTypes.func,
onOpenEditModal: PropTypes.func,
};

export default PatternCard;

+ 57
- 0
src/components/UI/CustomDrawer.js Просмотреть файл

@@ -0,0 +1,57 @@
import React from "react";
import PropType from "prop-types";
import Box from "@mui/material/Box";
import Drawer from "@mui/material/Drawer";
import filterIcon from "../../assets/images/filters.png";
import x from "../../assets/images/x.png";

const CustomDrawer = ({ title, open, onCloseDrawer, children }) => {
const list = () => (
<Box
sx={{
width: 360,
height: "100%",
borderRadius: "18px 0 0 18px",
padding: "36px",
}}
role="presentation"
onKeyDown={onCloseDrawer}
>
<div>
<div className="custom-filter-drawer-header-container">
<div className="custom-filter-drawer-header">
<img src={filterIcon} alt="filter_icon" />
<h3>Filteri</h3>
<p>
<sub>| {title}</sub>
</p>
</div>
<div
className="custom-filter-drawer-header-close"
onClick={onCloseDrawer}
>
<img src={x} alt="x" />
</div>
</div>
<div className="custom-filter-drawer-content">{children}</div>
</div>
</Box>
);

return (
<div>
<Drawer anchor="right" open={open} onClose={onCloseDrawer}>
{list()}
</Drawer>
</div>
);
};

CustomDrawer.propTypes = {
title: PropType.string,
open: PropType.bool,
onCloseDrawer: PropType.func,
children: PropType.any,
};

export default CustomDrawer;

+ 42
- 0
src/components/UI/CustomModal.js Просмотреть файл

@@ -0,0 +1,42 @@
import * as React from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import Modal from "@mui/material/Modal";

const style = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "background.paper",
border: "2px solid #000",
boxShadow: 24,
p: 4,
};

const CustomModal = ({ open, onCloseModal, children, classes }) => {
const handleClose = () => onCloseModal();

return (
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style} className={`custom-modal ${classes}`}>
{children}
</Box>
</Modal>
);
};

CustomModal.propTypes = {
open: PropTypes.bool,
onCloseModal: PropTypes.func,
children: PropTypes.any,
classes: PropTypes.string,
};

export default CustomModal;

+ 2
- 0
src/constants/pages.js Просмотреть файл

@@ -13,5 +13,7 @@ export const FORGOT_PASSWORD_CONFIRMATION_PAGE = '/forgot-password-confirmation'
export const RESET_PASSWORD_PAGE = '/reset-password';
export const SELECTION_PROCESS_PAGE = '/selectionFlow';
export const SELECTION_PROCESS_OF_APPLICANT_PAGE = '/selectionflow/:id';
export const PATTERNS_PAGE = '/patterns';
export const PATTERN_DETAILS_PAGE = '/patterns/:id';
export const SCHEDULE_PAGE = '/schedule'
export const STATS_PAGE = '/statistics';

+ 1
- 0
src/main.scss Просмотреть файл

@@ -32,6 +32,7 @@
@import './assets/styles/layout';
@import './assets/styles/overwrite';
@import './assets/styles/utility';
@import './assets/styles/components/patterns';


.flex-center{

+ 18
- 13
src/pages/AdsPage/AdsPage.js Просмотреть файл

@@ -9,7 +9,10 @@ import { useTranslation } from "react-i18next";
import AddAdModal from "../../components/Ads/AddAdModal";
import AdFilters from "../../components/Ads/AdFilters";
import { useDispatch } from "react-redux";
import { setAdsReq, setFilteredAdsReq } from "../../store/actions/ads/adsAction";
import {
setAdsReq,
setFilteredAdsReq,
} from "../../store/actions/ads/adsAction";
import { useSelector } from "react-redux";
import { selectAds } from "../../store/selectors/adsSelectors";
import { AD_DETAILS_PAGE } from "../../constants/pages";
@@ -48,30 +51,32 @@ const AdsPage = ({ history }) => {
useEffect(() => {
if (search) {
// history.push("/ads");
const searchParams = search.split('?')[1]
const technologyParams = searchParams.split('&').filter(x => x.includes('technologies'))
const technologies = []
technologyParams.forEach(p => {
const tech = p.split('=')
technologies.push(tech[1])

const searchParams = search.split("?")[1];
const technologyParams = searchParams
.split("&")
.filter((x) => x.includes("technologies"));
const technologies = [];
technologyParams.forEach((p) => {
const tech = p.split("=");
technologies.push(tech[1]);
});

const params = new URLSearchParams(search);

dispatch(
setFilteredAdsReq({
minExperience: params.get('minExperience'),
maxExperience: params.get('maxExperience'),
minExperience: params.get("minExperience"),
maxExperience: params.get("maxExperience"),
technologies,
workHour: params.get('workHour'),
employmentType: params.get('employmentType'),
workHour: params.get("workHour"),
employmentType: params.get("employmentType"),
})
);
} else {
dispatch(setAdsReq());
}
}, [])
}, []);

const handleToggleFiltersDrawer = () => {
setToggleFiltersDrawer((oldState) => !oldState);

+ 130
- 0
src/pages/PatternsPage/PatternDetailsPage.js Просмотреть файл

@@ -0,0 +1,130 @@
import React, { useEffect, useState } from "react";
import { IconButton } from "@mui/material";
import { Link } from "react-router-dom";
import plusIcon from "../../assets/images/plus.png";
import sendMessage from "../../assets/images/send_message.png";
import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { setPatternReq } from "../../store/actions/pattern/patternActions";
import { selectPattern } from "../../store/selectors/patternSelectors";

const PatternDetailsPage = () => {
const [emails, setEmails] = useState([]);
const [email, setEmail] = useState("");
const pattern = useSelector(selectPattern);
const { id } = useParams();
const dispatch = useDispatch();
const regex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/

useEffect(() => {
dispatch(setPatternReq({ id }));
}, []);

const addNewEmailHandler = () => {
setEmails((oldState) => [...oldState, email]);
setEmail("");
};

return (
<>
{!pattern && (
<div>
<p>Loading...</p>
</div>
)}
{pattern && (
<div className="pattern-details">
<div className="pattern-details-header">
<p>
<span>Napravljen:</span>{" "}
{new Date(pattern.createdAt).toLocaleDateString()}
</p>
</div>
<div className="pattern-details-card">
<div className="pattern-details-card-title">
<div className="pattern-details-card-title-title">
<h1>Šablon</h1>
</div>
<div className="pattern-details-card-title-sub">
<sub> | Zakazivanje termina</sub>
</div>
</div>
<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Screening test</p>
</div>
<div className="pattern-details-card-sub-card-emails">
{emails &&
emails.map((email, index) => (
<div
key={index}
className="pattern-details-card-sub-card-emails-email"
>
{email}
</div>
))}
</div>
</div>

<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Screening test</p>
</div>
<div className="pattern-details-card-sub-card-add-email">
<input
type="text"
onChange={(e) => setEmail(e.target.value)}
value={email}
placeholder="ex. petar.petrovic@mail.com"
/>
<button
onClick={addNewEmailHandler}
disabled={!regex.test(email)}
>
<img src={plusIcon} alt="plus" />
</button>
</div>
</div>

<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Teskt poruke</p>
</div>
<div className="pattern-details-card-sub-card-message-pattern">
<textarea
disabled
// value={`Postovani,

// Ovom prilikom Vas obavestavamo da je datum Screening testa zakazan za [selected Date]

// Srdacan pozdrav,
// Diligent HR Team`}
value={pattern.message}
></textarea>
</div>
</div>

<div className="pattern-details-card-buttons">
<Link className="ad-details-buttons-link" to="/patterns">
Nazad na sve šablone
</Link>
<IconButton className="c-btn c-btn--primary add-ad-btn">
<img
style={{
marginRight: "5px",
width: "12px",
height: "12px",
}}
src={sendMessage}
/>
PORUKU
</IconButton>
</div>
</div>
</div>
)}
</>
);
};

export default PatternDetailsPage;

+ 371
- 0
src/pages/PatternsPage/PatternsPage.js Просмотреть файл

@@ -0,0 +1,371 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import FilterButton from "../../components/Button/FilterButton";
import { useTheme } from "@mui/system";
import {
Checkbox,
FormControlLabel,
FormGroup,
IconButton,
useMediaQuery,
} from "@mui/material";
import userPageBtnIcon from "../../assets/images/userPageBtnIcon.png";
import PatternCard from "../../components/Patterns/PatternCard";
import { useDispatch, useSelector } from "react-redux";
import { setPatternsReq } from "../../store/actions/patterns/patternsActions";
import { selectPatterns } from "../../store/selectors/patternsSelectors";
import { selectProcesses } from "../../store/selectors/processesSelectors";
import { PATTERN_DETAILS_PAGE } from "../../constants/pages";
import CustomModal from "../../components/UI/CustomModal";
import plusIcon from "../../assets/images/plus.png";
import xIcon from "../../assets/images/x.png";
import { setProcessesReq } from "../../store/actions/processes/processesAction";
import { createPatternReq } from "../../store/actions/createPattern/createPatternActions";
import { updatePatternReq } from "../../store/actions/updatePattern/updatePatternActions";
import CustomDrawer from "../../components/UI/CustomDrawer";

const PatternsPage = ({ history }) => {
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down("sm"));
const [isShownEdit, setIsShownEdit] = useState(false);
const [openFilterDrawer, setOpenFilterDrawer] = useState(false);
const [openAddPatternModal, setOpenAddPatternModal] = useState(false);
const [openEditPatternModal, setOpenEditPatternModal] = useState(false);
const [editPattern, setEditPattern] = useState(null);
const [addPatternTitle, setAddPatternTitle] = useState("");
const [addPatternCategory, setAddPatternCategory] = useState(1);
const [addPatternMessage, setAddPatternMessage] = useState("");
const patterns = useSelector(selectPatterns);
const processes = useSelector(selectProcesses);
const dispatch = useDispatch();

useEffect(() => {
dispatch(setPatternsReq());
dispatch(setProcessesReq());
}, []);

useEffect(() => {
if (processes.length > 0) {
setAddPatternCategory(processes[0].id);
}
}, [processes]);

const closeAddPatternModalHandler = () => {
setOpenAddPatternModal(false);
};

const openEditModalHandler = (pattern) => {
setEditPattern({
id: pattern.id,
title: pattern.title,
createdAt: pattern.createdAt,
selectionLevelId: pattern.selectionLevel.id,
message: pattern.message,
});
setOpenEditPatternModal(true);
};

const closeEditPatternModalHandler = () => {
setEditPattern(null);
setOpenEditPatternModal(false);
};

const closeFilterDrawerHandler = () => {
setOpenFilterDrawer(false);
};

const submitAddPatternHandler = (e) => {
e.preventDefault();

if (addPatternTitle.length === 0 || addPatternMessage.length === 0) {
return;
}

dispatch(
createPatternReq({
title: addPatternTitle,
selectionLevelId: addPatternCategory,
message: addPatternMessage,
})
);

setOpenAddPatternModal(false);
setAddPatternTitle("");
setAddPatternCategory(processes[0].id);
setAddPatternMessage("");
};

const submitEditPatternHandler = (e) => {
e.preventDefault();

if (editPattern.title.length === 0 || editPattern.message.length === 0) {
return;
}

dispatch(updatePatternReq(editPattern));

setOpenEditPatternModal(false);
};

return (
<>
<CustomDrawer
title="Šabloni"
open={openFilterDrawer}
onCloseDrawer={closeFilterDrawerHandler}
>
<form>
<div className="custom-drawer">
<div>
<div className="custom-drawer-sub-card">
<div className="custom-drawer-sub-card-label">
<p>Kategorija</p>
</div>
<div className="custom-drawer-sub-card-content">
<FormGroup>
{processes.map((process) => (
<FormControlLabel
key={process.id}
control={<Checkbox value={process.name} />}
label={process.name}
/>
))}
</FormGroup>
</div>
</div>
<div className="custom-drawer-sub-card">
<div className="custom-drawer-sub-card-label">
<p>Datum kreiranja</p>
</div>
<div className="custom-drawer-sub-card-content">
<FormGroup style={{ marginBottom: "9px" }}>
<label className="custom-drawer-sub-card-content-sub-label">
Od
</label>
<input type="date" />
</FormGroup>
<FormGroup>
<label className="custom-drawer-sub-card-content-sub-label">
Do
</label>
<input type="date" />
</FormGroup>
</div>
</div>
</div>
<div className="custom-drawer-submit">
<button className="c-btn c-btn--primary">Pretrazi</button>
</div>
</div>
</form>
</CustomDrawer>
<CustomModal
open={openAddPatternModal}
onCloseModal={closeAddPatternModalHandler}
classes="add-pattern-modal"
>
<div className="add-pattern-modal-header">
<div className="add-pattern-modal-header-title">
<div className="add-pattern-modal-header-title-image">
<img src={plusIcon} alt="plus" />
</div>
<div className="add-pattern-modal-header-title-title">
<p>Dodavanje</p>
</div>
<div className="add-pattern-modal-header-title-sub">
<sub> | Šablon</sub>
</div>
</div>
<div
className="add-pattern-modal-header-close"
onClick={closeAddPatternModalHandler}
>
<img src={xIcon} alt="close" />
</div>
</div>
<form onSubmit={submitAddPatternHandler}>
<div className="add-pattern-modal-form-control">
<label>Naslov</label>
<input
type="text"
placeholder="ex. Datum HR intervjua"
onChange={(e) => setAddPatternTitle(e.target.value)}
value={addPatternTitle}
/>
</div>
<div className="add-pattern-modal-form-control">
<label>Kategorija</label>
<select
name="add-pattern-category"
value={addPatternCategory}
onChange={(e) => setAddPatternCategory(e.target.value)}
>
{processes.map((process) => (
<option key={process.id} value={process.id}>
{process.name}
</option>
))}
</select>
</div>
<div className="add-pattern-modal-form-control">
<label>Tekst poruke</label>
<textarea
rows="11"
value={addPatternMessage}
onChange={(e) => setAddPatternMessage(e.target.value)}
></textarea>
</div>
<div className="add-pattern-modal-form-control">
<input type="submit" value="DODAJ ŠABLON" />
</div>
</form>
</CustomModal>
<CustomModal
open={openEditPatternModal}
onCloseModal={closeEditPatternModalHandler}
classes="edit-pattern-modal"
>
<div className="edit-pattern-modal-header">
<div className="edit-pattern-modal-header-title">
<div className="edit-pattern-modal-header-title-image">
<img src={userPageBtnIcon} alt="plus" />
</div>
<div className="edit-pattern-modal-header-title-title">
<p>Uređivanje</p>
</div>
<div className="edit-pattern-modal-header-title-sub">
<sub> | Šablon</sub>
</div>
</div>
<div
className="edit-pattern-modal-header-close"
onClick={closeEditPatternModalHandler}
>
<img src={xIcon} alt="close" />
</div>
</div>
<form onSubmit={submitEditPatternHandler}>
<div className="edit-pattern-modal-form-control">
<label>Naslov</label>
<input
type="text"
placeholder="ex. Datum HR intervjua"
onChange={(e) =>
setEditPattern((oldState) => ({
...oldState,
title: e.target.value,
}))
}
value={editPattern ? editPattern.title : ""}
/>
</div>
<div className="edit-pattern-modal-form-control">
<label>Kategorija</label>
<select
name="edit-pattern-category"
value={editPattern ? editPattern.selectionLevelId : 1}
onChange={(e) =>
setEditPattern((oldState) => ({
...oldState,
selectionLevelId: e.target.value,
}))
}
>
{processes.map((process) => (
<option key={process.id} value={process.id}>
{process.name}
</option>
))}
</select>
</div>
<div className="edit-pattern-modal-form-control">
<label>Tekst poruke</label>
<textarea
rows="11"
onChange={(e) =>
setEditPattern((oldState) => ({
...oldState,
message: e.target.value,
}))
}
value={editPattern ? editPattern.message : ""}
></textarea>
</div>
<div className="edit-pattern-modal-form-control">
<input type="submit" value="UREDI ŠABLON" />
</div>
</form>
</CustomModal>
<div className="patterns">
<div className="patterns-header">
<div>
<h1>Napravljeni Šabloni</h1>
</div>
<div>
<IconButton
onClick={() => setIsShownEdit((oldState) => !oldState)}
className={`c-btn--primary-outlined editEnableBtn c-btn userPageBtn ${
isShownEdit && "pattern-header-active-button"
}`}
>
{!matches && "Režim uređivanja"}
<img
style={{
position: "relative",
top: -0.25,
paddingLeft: matches ? "0px" : "10px",
}}
src={userPageBtnIcon}
/>
</IconButton>
<FilterButton onShowFilters={() => setOpenFilterDrawer(true)} />
</div>
</div>
<div className="patterns-cards">
{!patterns && (
<div>
<p>Loading...</p>
</div>
)}
{patterns && patterns.length === 0 && (
<div>
<p>Trenutno nema dodatih sablona</p>
</div>
)}
{patterns &&
patterns.length > 0 &&
patterns.map((pattern) => (
<div className="pattern-card-parent" key={pattern.id}>
<PatternCard
createdAt={pattern.createdAt}
title={pattern.title}
selectionProcess={pattern.selectionLevel.name}
onOpenEditModal={openEditModalHandler.bind(this, pattern)}
isShownEdit={isShownEdit}
onShowPatternDetails={() =>
history.push(
PATTERN_DETAILS_PAGE.replace(":id", pattern.id)
)
}
/>
</div>
))}
</div>
<div className="patterns-button">
<IconButton
className="c-btn c-btn--primary add-ad-btn"
onClick={() => setOpenAddPatternModal(true)}
>
Dodaj Šablon
</IconButton>
</div>
</div>
</>
);
};

PatternsPage.propTypes = {
history: PropTypes.any,
};

export default PatternsPage;

+ 8
- 2
src/request/apiEndpoints.js Просмотреть файл

@@ -29,8 +29,8 @@ export default {
technologies: {
allTechnologies: base + "/technologies",
},
comments:{
addComment:base + '/comments'
comments: {
addComment: base + "/comments",
},
processes: {
allLevels: base + "/selectionlevels",
@@ -39,6 +39,12 @@ export default {
getApplicantProcesses: base + "/applicants/processes",
// allProcesses: base + "/selectionprocesses",
},
patterns: {
allPatterns: base + "/patterns",
patternById: base + "/patterns/:id",
createPattern: base + "/patterns",
updatePattern: base + "/patterns/:id",
},
stats:{
stats: base + "/stats"
}

+ 14
- 0
src/request/patternsRequest.js Просмотреть файл

@@ -0,0 +1,14 @@
import { getRequest, postRequest, putRequest } from ".";
import apiEndpoints from "./apiEndpoints";

export const getAllPatterns = () =>
getRequest(apiEndpoints.patterns.allPatterns);
export const getPatternById = (id) =>
getRequest(apiEndpoints.patterns.patternById.replace(":id", id));
export const createPatternRequest = (payload) =>
postRequest(apiEndpoints.patterns.createPattern, payload);
export const updatePatternRequest = (payload) =>
putRequest(
apiEndpoints.patterns.updatePattern.replace(":id", payload.id),
payload
);

+ 11
- 0
src/store/actions/createPattern/createPatternActionConstants.js Просмотреть файл

@@ -0,0 +1,11 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";

const CREATE_PATTERN_SCOPE = "CREATE_PATTERN";

export const CREATE_PATTERN_REQ = createFetchType(CREATE_PATTERN_SCOPE);
export const CREATE_PATTERN_ERR = createErrorType(CREATE_PATTERN_SCOPE);
export const CREATE_PATTERN_SUCCESS = createSuccessType(CREATE_PATTERN_SCOPE);

+ 20
- 0
src/store/actions/createPattern/createPatternActions.js Просмотреть файл

@@ -0,0 +1,20 @@
import {
CREATE_PATTERN_REQ,
CREATE_PATTERN_ERR,
CREATE_PATTERN_SUCCESS,
} from "./createPatternActionConstants";

export const createPatternReq = (payload) => ({
type: CREATE_PATTERN_REQ,
payload,
});

export const createPatternError = (payload) => ({
type: CREATE_PATTERN_ERR,
payload,
});

export const createPattern = (payload) => ({
type: CREATE_PATTERN_SUCCESS,
payload,
});

+ 11
- 0
src/store/actions/pattern/patternActionConstants.js Просмотреть файл

@@ -0,0 +1,11 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";

const FETCH_PATTERN_SCOPE = "FETCH_PATTERN";

export const FETCH_PATTERN_REQ = createFetchType(FETCH_PATTERN_SCOPE);
export const FETCH_PATTERN_ERR = createErrorType(FETCH_PATTERN_SCOPE);
export const FETCH_PATTERN_SUCCESS = createSuccessType(FETCH_PATTERN_SCOPE);

+ 20
- 0
src/store/actions/pattern/patternActions.js Просмотреть файл

@@ -0,0 +1,20 @@
import {
FETCH_PATTERN_REQ,
FETCH_PATTERN_ERR,
FETCH_PATTERN_SUCCESS,
} from "./patternActionConstants";

export const setPatternReq = (payload) => ({
type: FETCH_PATTERN_REQ,
payload,
});

export const setPatternError = (payload) => ({
type: FETCH_PATTERN_ERR,
payload,
});

export const setPattern = (payload) => ({
type: FETCH_PATTERN_SUCCESS,
payload,
});

+ 11
- 0
src/store/actions/patterns/patternsActionConstants.js Просмотреть файл

@@ -0,0 +1,11 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";

const FETCH_PATTERNS_SCOPE = "FETCH_PATTERNS";

export const FETCH_PATTERNS_REQ = createFetchType(FETCH_PATTERNS_SCOPE);
export const FETCH_PATTERNS_ERR = createErrorType(FETCH_PATTERNS_SCOPE);
export const FETCH_PATTERNS_SUCCESS = createSuccessType(FETCH_PATTERNS_SCOPE);

+ 19
- 0
src/store/actions/patterns/patternsActions.js Просмотреть файл

@@ -0,0 +1,19 @@
import {
FETCH_PATTERNS_REQ,
FETCH_PATTERNS_ERR,
FETCH_PATTERNS_SUCCESS,
} from "./patternsActionConstants";

export const setPatternsReq = () => ({
type: FETCH_PATTERNS_REQ,
});

export const setPatternsError = (payload) => ({
type: FETCH_PATTERNS_ERR,
payload,
});

export const setPatterns = (payload) => ({
type: FETCH_PATTERNS_SUCCESS,
payload,
});

+ 11
- 0
src/store/actions/updatePattern/updatePatternActionConstants.js Просмотреть файл

@@ -0,0 +1,11 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";

const UPDATE_PATTERN_SCOPE = "UPDATE_PATTERN";

export const UPDATE_PATTERN_REQ = createFetchType(UPDATE_PATTERN_SCOPE);
export const UPDATE_PATTERN_ERR = createErrorType(UPDATE_PATTERN_SCOPE);
export const UPDATE_PATTERN_SUCCESS = createSuccessType(UPDATE_PATTERN_SCOPE);

+ 20
- 0
src/store/actions/updatePattern/updatePatternActions.js Просмотреть файл

@@ -0,0 +1,20 @@
import {
UPDATE_PATTERN_REQ,
UPDATE_PATTERN_ERR,
UPDATE_PATTERN_SUCCESS,
} from "./updatePatternActionConstants";

export const updatePatternReq = (payload) => ({
type: UPDATE_PATTERN_REQ,
payload,
});

export const updatePatternError = (payload) => ({
type: UPDATE_PATTERN_ERR,
payload,
});

export const updatePattern = (payload) => ({
type: UPDATE_PATTERN_SUCCESS,
payload,
});

+ 8
- 0
src/store/reducers/index.js Просмотреть файл

@@ -18,6 +18,10 @@ import applicantWithProcessesReducer from "./processes/applicantWithProcessesRed
import userDetailsReducer from "./user/userDetailsReducer";
import inviteUserReducer from "./user/inviteUserReducer";
import statusReducer from "./processes/statusReducer";
import patternsReducer from "./pattern/patternsReducer";
import patternReducer from "./pattern/patternReducer";
import createPatternReducer from "./pattern/createPatternReducer";
import updatePatternReducer from "./pattern/updatePatternReducer";
import statsReducer from "./stats/statsReducer";

export default combineReducers({
@@ -40,5 +44,9 @@ export default combineReducers({
userDetails: userDetailsReducer,
invite: inviteUserReducer,
statuses: statusReducer,
patterns: patternsReducer,
pattern: patternReducer,
createPattern: createPatternReducer,
updatePattern: updatePatternReducer,
stats: statsReducer,
});

+ 32
- 0
src/store/reducers/pattern/createPatternReducer.js Просмотреть файл

@@ -0,0 +1,32 @@
import {
CREATE_PATTERN_ERR,
CREATE_PATTERN_SUCCESS,
} from "../../actions/createPattern/createPatternActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
pattern: null,
errorMessage: "",
};

export default createReducer(
{
[CREATE_PATTERN_SUCCESS]: setCreatePattern,
[CREATE_PATTERN_ERR]: setCreatePatternErrorMessage,
},
initialState
);

function setCreatePattern(state, action) {
return {
...state,
pattern: action.payload,
};
}

function setCreatePatternErrorMessage(state, action) {
return {
...state,
errorMessage: action.payload,
};
}

+ 26
- 0
src/store/reducers/pattern/patternReducer.js Просмотреть файл

@@ -0,0 +1,26 @@
import createReducer from "../../utils/createReducer";
import {
FETCH_PATTERN_SUCCESS,
FETCH_PATTERN_ERR,
} from "../../actions/pattern/patternActionConstants";

const initialState = {
pattern: null,
errorMessage: "",
};

export default createReducer(
{
[FETCH_PATTERN_SUCCESS]: setStatePattern,
[FETCH_PATTERN_ERR]: setStateErrorMessage,
},
initialState
);

function setStatePattern(state, action) {
return { ...state, pattern: action.payload };
}

function setStateErrorMessage(state, action) {
return { ...state, errorMessage: action.payload };
}

+ 32
- 0
src/store/reducers/pattern/patternsReducer.js Просмотреть файл

@@ -0,0 +1,32 @@
import {
FETCH_PATTERNS_ERR,
FETCH_PATTERNS_SUCCESS,
} from "../../actions/patterns/patternsActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
patterns: [],
errorMessage: "",
};

export default createReducer(
{
[FETCH_PATTERNS_SUCCESS]: setStatePatterns,
[FETCH_PATTERNS_ERR]: setPatternsErrorMessage,
},
initialState
);

function setStatePatterns(state, action) {
return {
...state,
patterns: action.payload,
};
}

function setPatternsErrorMessage(state, action) {
return {
...state,
errorMessage: action.payload,
};
}

+ 32
- 0
src/store/reducers/pattern/updatePatternReducer.js Просмотреть файл

@@ -0,0 +1,32 @@
import {
UPDATE_PATTERN_ERR,
UPDATE_PATTERN_SUCCESS,
} from "../../actions/updatePattern/updatePatternActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
pattern: null,
errorMessage: "",
};

export default createReducer(
{
[UPDATE_PATTERN_SUCCESS]: setUpdatePattern,
[UPDATE_PATTERN_ERR]: setUpdatePatternErrorMessage,
},
initialState
);

function setUpdatePattern(state, action) {
return {
...state,
pattern: action.payload,
};
}

function setUpdatePatternErrorMessage(state, action) {
return {
...state,
errorMessage: action.payload,
};
}

+ 4
- 0
src/store/saga/adsSaga.js Просмотреть файл

@@ -68,6 +68,10 @@ export function* createAd({ payload }) {
const result = yield call(createNewAd, payload);
const ad = result.data;
yield put(setCreateAd(ad));
const resultAds = yield call(getAllAds);
yield put(setAds(resultAds.data));
const resultArchiveAds = yield call(getAllArchiveAds);
yield put(setArchiveAds(resultArchiveAds.data));
} catch (error) {
yield put(setCreateAdError(error));
}

+ 3
- 1
src/store/saga/index.js Просмотреть файл

@@ -1,10 +1,11 @@
import { all } from "redux-saga/effects";
import adsSaga from "./adsSaga";
import candidatesSaga from './candidatesSaga';
import candidatesSaga from "./candidatesSaga";
import loginSaga from "./loginSaga";
import technologiesSaga from "./technologiesSaga";
import usersSaga from "./usersSaga";
import processesSaga from "./processSaga";
import patternsSage from "./patternsSaga";
import statsSaga from "./statsSaga";

export default function* rootSaga() {
@@ -15,6 +16,7 @@ export default function* rootSaga() {
technologiesSaga(),
candidatesSaga(),
processesSaga(),
patternsSage(),
statsSaga()
]);
}

+ 73
- 0
src/store/saga/patternsSaga.js Просмотреть файл

@@ -0,0 +1,73 @@
import { all, call, put, takeLatest } from "redux-saga/effects";
import {
createPatternRequest,
getAllPatterns,
getPatternById,
updatePatternRequest,
} from "../../request/patternsRequest";
import {
setPatterns,
setPatternsError,
} from "../actions/patterns/patternsActions";
import { setPattern, setPatternError } from "../actions/pattern/patternActions";
import {
createPattern,
createPatternError,
} from "../actions/createPattern/createPatternActions";
import { FETCH_PATTERNS_REQ } from "../actions/patterns/patternsActionConstants";
import { FETCH_PATTERN_REQ } from "../actions/pattern/patternActionConstants";
import { CREATE_PATTERN_REQ } from "../actions/createPattern/createPatternActionConstants";
import { UPDATE_PATTERN_REQ } from "../actions/updatePattern/updatePatternActionConstants";
import {
updatePattern,
updatePatternError,
} from "../actions/updatePattern/updatePatternActions";

export function* getPatterns() {
try {
const result = yield call(getAllPatterns);
yield put(setPatterns(result.data));
} catch (error) {
yield put(setPatternsError(error));
}
}

export function* getPattern({ payload }) {
try {
const result = yield call(getPatternById, payload.id);
yield put(setPattern(result.data));
} catch (error) {
yield put(setPatternError(error));
}
}

export function* createPatternSaga({ payload }) {
try {
const result = yield call(createPatternRequest, payload);
yield put(createPattern(result.data));
const resultPatterns = yield call(getAllPatterns);
yield put(setPatterns(resultPatterns.data));
} catch (error) {
yield put(createPatternError(error));
}
}

export function* updatePatternSaga({ payload }) {
try {
const result = yield call(updatePatternRequest, payload);
yield put(updatePattern(result.data));
const resultPatterns = yield call(getAllPatterns);
yield put(setPatterns(resultPatterns.data));
} catch (error) {
yield put(updatePatternError(error));
}
}

export default function* adsSaga() {
yield all([
takeLatest(FETCH_PATTERNS_REQ, getPatterns),
takeLatest(FETCH_PATTERN_REQ, getPattern),
takeLatest(CREATE_PATTERN_REQ, createPatternSaga),
takeLatest(UPDATE_PATTERN_REQ, updatePatternSaga),
]);
}

+ 13
- 0
src/store/selectors/patternSelectors.js Просмотреть файл

@@ -0,0 +1,13 @@
import { createSelector } from "@reduxjs/toolkit";

export const patternSelector = (state) => state.pattern;

export const selectPattern = createSelector(
patternSelector,
(state) => state.pattern
);

export const selectPatternError = createSelector(
patternSelector,
(state) => state.errorMessage
);

+ 13
- 0
src/store/selectors/patternsSelectors.js Просмотреть файл

@@ -0,0 +1,13 @@
import { createSelector } from "@reduxjs/toolkit";

export const patternsSelector = (state) => state.patterns;

export const selectPatterns = createSelector(
patternsSelector,
(state) => state.patterns
);

export const selectPatternsError = createSelector(
patternsSelector,
(state) => state.errorMessage
);

Загрузка…
Отмена
Сохранить