| border-radius: 9px; | border-radius: 9px; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| } | } | ||||
| .active-ads-ads-no-ads { | |||||
| height: 75vh; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| text-align: center; | |||||
| width: 466px; | |||||
| margin: 0 auto; | |||||
| @include media-below($bp-xl) { | |||||
| width: 300px; | |||||
| } | |||||
| } | |||||
| .active-ads-ads-no-ads h1 { | |||||
| margin-bottom: 18px !important; | |||||
| } | |||||
| .active-ads-ads-no-ads p { | |||||
| margin-bottom: 36px !important; | |||||
| } | |||||
| .active-ads-ads-ad { | .active-ads-ads-ad { | ||||
| padding-left: 81px; | padding-left: 81px; | ||||
| } | } | ||||
| } | } | ||||
| .archive-ads-no-active-ads { | |||||
| padding-bottom: 136px !important; | |||||
| } | |||||
| .archive-ad { | .archive-ad { | ||||
| box-sizing: border-box; | box-sizing: border-box; | ||||
| display: flex; | display: flex; | ||||
| background-color: $mainBlueLight !important; | background-color: $mainBlueLight !important; | ||||
| } | } | ||||
| .ad-card-buttons-button{ | |||||
| .ad-card-buttons-button { | |||||
| display: flex; | display: flex; | ||||
| flex-direction: row; | flex-direction: row; | ||||
| justify-content: center; | justify-content: center; | ||||
| } | } | ||||
| } | } | ||||
| .add-ad-no-ads { | |||||
| margin: 0 !important; | |||||
| padding: 0 !important; | |||||
| } | |||||
| .ad-filters-header-container { | .ad-filters-header-container { | ||||
| display: flex; | display: flex; | ||||
| justify-content: space-between; | justify-content: space-between; | ||||
| .hiddenAd { | .hiddenAd { | ||||
| visibility: hidden !important; | visibility: hidden !important; | ||||
| } | |||||
| .add-ad-modal { | |||||
| padding: 36px !important; | |||||
| border: none !important; | |||||
| border-radius: 18px; | |||||
| min-height: 591px !important; | |||||
| width: 512px !important; | |||||
| } | |||||
| .add-ad-modal-header { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| margin-bottom: 18px !important; | |||||
| } | |||||
| .add-ad-modal-header img { | |||||
| width: 18px; | |||||
| height: 18px; | |||||
| } | |||||
| .add-ad-modal-header-title { | |||||
| display: flex; | |||||
| align-items: flex-end; | |||||
| } | |||||
| .add-ad-modal-header-title > * { | |||||
| margin-right: 6px; | |||||
| } | |||||
| .add-ad-modal-header-title-span { | |||||
| color: $mainBlue; | |||||
| } | |||||
| .add-ad-modal-header-icon button { | |||||
| background-color: transparent; | |||||
| border: none; | |||||
| cursor: pointer; | |||||
| } | |||||
| .add-ad-modal-header-icon img { | |||||
| width: 9px !important; | |||||
| height: 12px !important; | |||||
| } | |||||
| .add-ad-modal-stages { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: space-between; | |||||
| min-height: calc(591px - 36px - 36px - 20.8px - 18px) !important; | |||||
| } | |||||
| .add-ad-modal-stage { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: space-between; | |||||
| min-height: calc(591px - 36px - 36px - 20.8px - 18px) !important; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-bottom: 9px; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-third { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-bottom: 9px; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card label, | |||||
| .add-ad-modal-stage-sub-card-third label { | |||||
| margin-bottom: 4.5px !important; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-title { | |||||
| margin-bottom: 9px; | |||||
| font-weight: bold; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card input, | |||||
| .add-ad-modal-stage-sub-card-third textarea { | |||||
| padding: 9px; | |||||
| border-radius: 7px; | |||||
| border: 1px solid #e4e4e4; | |||||
| outline: none; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-third textarea { | |||||
| resize: none; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-checkboxes { | |||||
| padding: 0 9px !important; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-checkboxes { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| justify-content: flex-start; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-checkboxes .MuiFormControlLabel-root { | |||||
| width: calc(100% / 3) !important; | |||||
| margin: 0 !important; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-buttons { | |||||
| display: flex; | |||||
| } | |||||
| .add-ad-modal-stage-sub-card-buttons button { | |||||
| margin-right: 9px; | |||||
| } | |||||
| .add-ad-modal-actions { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| } | |||||
| .add-ad-modal-actions button { | |||||
| padding: 18px 72px !important; | |||||
| } | } |
| import Slider from "@mui/material/Slider"; | import Slider from "@mui/material/Slider"; | ||||
| import filterIcon from "../../assets/images/filter_vector.png"; | import filterIcon from "../../assets/images/filter_vector.png"; | ||||
| import x from "../../assets/images/x.png"; | import x from "../../assets/images/x.png"; | ||||
| import { changeIsCheckedValue } from "../../store/actions/technologies/technologiesActions"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { setFilteredAdsReq } from "../../store/actions/ads/adsAction"; | |||||
| const AdFilters = ({ open, handleClose }) => { | |||||
| const [value, setValue] = useState([0, 10]); | |||||
| const AdFilters = ({ open, handleClose, technologies }) => { | |||||
| const [sliderValue, setSliderValue] = useState([0, 10]); | |||||
| const [employmentType, setEmploymentType] = useState("Work"); | |||||
| const [workHour, setWorkHour] = useState("FullTime"); | |||||
| const dispatch = useDispatch(); | |||||
| const handleSliderChange = (_, newValue) => { | const handleSliderChange = (_, newValue) => { | ||||
| setValue(newValue); | |||||
| setSliderValue(newValue); | |||||
| }; | |||||
| const onSubmitFilters = () => { | |||||
| const tech = technologies | |||||
| .filter((tech) => tech.isChecked === true) | |||||
| .map((tech) => tech.name); | |||||
| if(tech.length === 0) { | |||||
| return; | |||||
| } | |||||
| dispatch( | |||||
| setFilteredAdsReq({ | |||||
| minExperience: sliderValue[0], | |||||
| maxExperience: sliderValue[1], | |||||
| technologies: tech, | |||||
| workHour, | |||||
| employmentType, | |||||
| }) | |||||
| ); | |||||
| handleClose(); | |||||
| }; | |||||
| const handleCheckboxes = (e) => { | |||||
| const { value } = e.target; | |||||
| dispatch(changeIsCheckedValue(value)); | |||||
| }; | |||||
| const employmentTypeHandler = (type) => { | |||||
| setEmploymentType(type); | |||||
| }; | |||||
| const workHourHandler = (type) => { | |||||
| setWorkHour(type); | |||||
| }; | }; | ||||
| const list = () => ( | const list = () => ( | ||||
| <div className="ad-filters-experience-slider"> | <div className="ad-filters-experience-slider"> | ||||
| <Slider | <Slider | ||||
| getAriaLabel={() => "Temperature range"} | getAriaLabel={() => "Temperature range"} | ||||
| value={value} | |||||
| value={sliderValue} | |||||
| onChange={handleSliderChange} | onChange={handleSliderChange} | ||||
| valueLabelDisplay="auto" | valueLabelDisplay="auto" | ||||
| max={20} | max={20} | ||||
| </div> | </div> | ||||
| <div className="ad-filters-technologies-checkboxes"> | <div className="ad-filters-technologies-checkboxes"> | ||||
| <FormGroup> | <FormGroup> | ||||
| <FormControlLabel control={<Checkbox />} label="HTML/CSS" /> | |||||
| <FormControlLabel control={<Checkbox />} label="Vanilla JS" /> | |||||
| <FormControlLabel control={<Checkbox />} label="React" /> | |||||
| <FormControlLabel control={<Checkbox />} label="Angular" /> | |||||
| <FormControlLabel control={<Checkbox />} label="SQL" /> | |||||
| <FormControlLabel control={<Checkbox />} label="Node.js" /> | |||||
| <FormControlLabel control={<Checkbox />} label="PHP" /> | |||||
| <FormControlLabel control={<Checkbox />} label="Git" /> | |||||
| {technologies.map((technology, index) => ( | |||||
| <FormControlLabel | |||||
| key={index} | |||||
| control={ | |||||
| <Checkbox | |||||
| onChange={handleCheckboxes} | |||||
| value={technology.name} | |||||
| checked={technology.isChecked} | |||||
| /> | |||||
| } | |||||
| label={technology.name} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | </FormGroup> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <p>Tip zaposlenja</p> | <p>Tip zaposlenja</p> | ||||
| </div> | </div> | ||||
| <div className="ad-filters-employment-type"> | <div className="ad-filters-employment-type"> | ||||
| <button className="c-btn c-btn--primary-outlined">Intership</button> | |||||
| <button className="c-btn c-btn--primary">Posao</button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Intership" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Intership")} | |||||
| > | |||||
| Intership | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Work" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Work")} | |||||
| > | |||||
| Posao | |||||
| </button> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className="ad-filters-technologies"> | <div className="ad-filters-technologies"> | ||||
| <p>Radno vreme</p> | <p>Radno vreme</p> | ||||
| </div> | </div> | ||||
| <div className="ad-filters-employment-type"> | <div className="ad-filters-employment-type"> | ||||
| <button className="c-btn c-btn--primary-outlined">Part-time</button> | |||||
| <button className="c-btn c-btn--primary-outlined">Full-time</button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "PartTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "PartTime")} | |||||
| > | |||||
| Part-time | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "FullTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "FullTime")} | |||||
| > | |||||
| Full-time | |||||
| </button> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className="ad-filters-search"> | <div className="ad-filters-search"> | ||||
| <button className="c-btn c-btn--primary">Pretrazi</button> | |||||
| <button onClick={onSubmitFilters} className="c-btn c-btn--primary"> | |||||
| Pretrazi | |||||
| </button> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </Box> | </Box> | ||||
| AdFilters.propTypes = { | AdFilters.propTypes = { | ||||
| open: PropType.any, | open: PropType.any, | ||||
| handleClose: PropType.func, | handleClose: PropType.func, | ||||
| technologies: PropType.any, | |||||
| }; | }; | ||||
| export default AdFilters; | export default AdFilters; |
| import React from "react"; | |||||
| import React, { useEffect, useState } from "react"; | |||||
| import PropType from "prop-types"; | import PropType from "prop-types"; | ||||
| import Box from "@mui/material/Box"; | import Box from "@mui/material/Box"; | ||||
| import Modal from "@mui/material/Modal"; | import Modal from "@mui/material/Modal"; | ||||
| import plus from "../../assets/images/plus.png"; | |||||
| import xIcon from "../../assets/images/x.png"; | |||||
| import AddAdModalFirstStage from "./AddAdModalFirstStage"; | |||||
| import AddAdModalSecondStage from "./AddAdModalSecondStage"; | |||||
| import AddAdModalThirdStage from "./AddAdModalThirdStage"; | |||||
| import { useSelector, useDispatch } from "react-redux"; | |||||
| import { setTechnologiesAddAdReq } from "../../store/actions/addAdTechnologies/addAdTechnologiesActions"; | |||||
| import { setCreateAdReq } from "../../store/actions/createAd/createAdActions"; | |||||
| const style = { | const style = { | ||||
| position: "absolute", | position: "absolute", | ||||
| bgcolor: "background.paper", | bgcolor: "background.paper", | ||||
| border: "2px solid #000", | border: "2px solid #000", | ||||
| boxShadow: 24, | boxShadow: 24, | ||||
| pt: 2, | |||||
| px: 4, | |||||
| pb: 3, | |||||
| }; | }; | ||||
| const AddAdModal = ({ open, handleClose }) => { | const AddAdModal = ({ open, handleClose }) => { | ||||
| const [stage, setStage] = useState(1); | |||||
| const [title, setTitle] = useState(""); | |||||
| const [employmentType, setEmploymentType] = useState("Work"); | |||||
| const [workHour, setWorkHour] = useState("FullTime"); | |||||
| const [expiredAt, setExpiredAt] = useState(new Date()); | |||||
| const [experience, setExperience] = useState(0); | |||||
| const [keyResponsibilities, setKeyResponsibilities] = useState(""); | |||||
| const [requirements, setRequirements] = useState(""); | |||||
| const [whatWeOffer, setWhatWeOffer] = useState(""); | |||||
| const technologies = useSelector( | |||||
| (state) => state.addAdTechnologies.technologies | |||||
| ); | |||||
| const dispatch = useDispatch(); | |||||
| useEffect(() => { | |||||
| dispatch(setTechnologiesAddAdReq()); | |||||
| }, []); | |||||
| const addAdHandler = () => { | |||||
| const technologiesIds = technologies | |||||
| .filter((x) => x.isChecked === true) | |||||
| .map((x) => x.technologyId); | |||||
| dispatch( | |||||
| setCreateAdReq({ | |||||
| title, | |||||
| minimumExperience: experience, | |||||
| createdAt: new Date(), | |||||
| expiredAt, | |||||
| keyResponsibilities, | |||||
| requirements, | |||||
| offer: whatWeOffer, | |||||
| workHour, | |||||
| employmentType, | |||||
| technologiesIds, | |||||
| }) | |||||
| ); | |||||
| handleClose(); | |||||
| }; | |||||
| const completeFirstStage = () => { | |||||
| console.log(title, employmentType, workHour, expiredAt); | |||||
| }; | |||||
| const incrementStageHandler = () => { | |||||
| setStage((oldState) => oldState + 1); | |||||
| }; | |||||
| const decrementStageHandler = () => { | |||||
| setStage((oldState) => oldState - 1); | |||||
| }; | |||||
| return ( | return ( | ||||
| <Modal | <Modal | ||||
| open={open} | open={open} | ||||
| aria-labelledby="parent-modal-title" | aria-labelledby="parent-modal-title" | ||||
| aria-describedby="parent-modal-description" | aria-describedby="parent-modal-description" | ||||
| > | > | ||||
| <Box sx={{ ...style, width: 400 }}> | |||||
| <h2 id="parent-modal-title">Text in a modal</h2> | |||||
| <p id="parent-modal-description"> | |||||
| Duis mollis, est non commodo luctus, nisi erat porttitor ligula. | |||||
| </p> | |||||
| <Box sx={{ ...style, width: 512 }} className="add-ad-modal"> | |||||
| <div className="add-ad-modal-header"> | |||||
| <div className="add-ad-modal-header-title"> | |||||
| <img src={plus} alt="plus" /> | |||||
| <h3>Dodavanje</h3> | |||||
| <h4> | |||||
| <span className="add-ad-modal-header-title-span">| Oglas</span> | |||||
| </h4> | |||||
| <h4></h4> | |||||
| </div> | |||||
| <div className="add-ad-modal-header-icon"> | |||||
| <button onClick={handleClose}> | |||||
| <img src={xIcon} alt="xIcon" /> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stages"> | |||||
| {stage === 1 && ( | |||||
| <AddAdModalFirstStage | |||||
| title={title} | |||||
| setTitle={setTitle} | |||||
| employmentType={employmentType} | |||||
| setEmploymentType={setEmploymentType} | |||||
| workHour={workHour} | |||||
| setWorkHour={setWorkHour} | |||||
| expiredAt={expiredAt} | |||||
| setExpiredAt={setExpiredAt} | |||||
| onCompleteFirstStage={completeFirstStage} | |||||
| onIncrementStage={incrementStageHandler} | |||||
| onDecrementStage={decrementStageHandler} | |||||
| /> | |||||
| )} | |||||
| {stage === 2 && ( | |||||
| <AddAdModalSecondStage | |||||
| onIncrementStage={incrementStageHandler} | |||||
| onDecrementStage={decrementStageHandler} | |||||
| technologies={technologies} | |||||
| experience={experience} | |||||
| setExperience={setExperience} | |||||
| /> | |||||
| )} | |||||
| {stage === 3 && ( | |||||
| <AddAdModalThirdStage | |||||
| onDecrementStage={decrementStageHandler} | |||||
| keyResponsibilities={keyResponsibilities} | |||||
| setKeyResponsibilities={setKeyResponsibilities} | |||||
| requirements={requirements} | |||||
| setRequirements={setRequirements} | |||||
| whatWeOffer={whatWeOffer} | |||||
| setWhatWeOffer={setWhatWeOffer} | |||||
| onAddAd={addAdHandler} | |||||
| /> | |||||
| )} | |||||
| </div> | |||||
| </Box> | </Box> | ||||
| </Modal> | </Modal> | ||||
| ); | ); | ||||
| AddAdModal.propTypes = { | AddAdModal.propTypes = { | ||||
| open: PropType.any, | open: PropType.any, | ||||
| handleClose: PropType.func | |||||
| handleClose: PropType.func, | |||||
| }; | }; | ||||
| export default AddAdModal; | export default AddAdModal; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| const AddAdModalFirstStage = ({ | |||||
| onIncrementStage, | |||||
| onDecrementStage, | |||||
| onCompleteFirstStage, | |||||
| title, | |||||
| employmentType, | |||||
| workHour, | |||||
| setTitle, | |||||
| setEmploymentType, | |||||
| setWorkHour, | |||||
| expiredAt, | |||||
| setExpiredAt, | |||||
| }) => { | |||||
| const completeStageHandler = () => { | |||||
| if(title.length === 0) { | |||||
| return; | |||||
| } | |||||
| onIncrementStage(); | |||||
| onCompleteFirstStage(); | |||||
| }; | |||||
| const employmentTypeHandler = (type) => { | |||||
| setEmploymentType(type); | |||||
| }; | |||||
| const workHourHandler = (type) => { | |||||
| setWorkHour(type); | |||||
| }; | |||||
| return ( | |||||
| <div className="add-ad-modal-stage"> | |||||
| <div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>Naslov</label> | |||||
| <input | |||||
| type="text" | |||||
| value={title} | |||||
| placeholder="ex. Medior React Developer" | |||||
| onChange={(e) => setTitle(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>Tip zaposlenja</label> | |||||
| <div className="add-ad-modal-stage-sub-card-buttons"> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Work" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Work")} | |||||
| > | |||||
| Posao | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Intership" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Intership")} | |||||
| > | |||||
| Intership | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>Radno vreme</label> | |||||
| <div className="add-ad-modal-stage-sub-card-buttons"> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "PartTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "PartTime")} | |||||
| > | |||||
| Part-time | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "FullTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "FullTime")} | |||||
| > | |||||
| Full-time | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>Datum isteka oglasa</label> | |||||
| <input | |||||
| type="date" | |||||
| placeholder="ex" | |||||
| value={expiredAt} | |||||
| onChange={(e) => setExpiredAt(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-actions"> | |||||
| <button | |||||
| className="c-btn c-btn--primary-outlined" | |||||
| disabled | |||||
| onClick={onDecrementStage} | |||||
| > | |||||
| NAZAD | |||||
| </button> | |||||
| <button className="c-btn c-btn--primary" onClick={completeStageHandler}> | |||||
| NASTAVI | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AddAdModalFirstStage.propTypes = { | |||||
| onCompleteFirstStage: PropTypes.func, | |||||
| onIncrementStage: PropTypes.func, | |||||
| onDecrementStage: PropTypes.func, | |||||
| title: PropTypes.string, | |||||
| employmentType: PropTypes.string, | |||||
| workHour: PropTypes.string, | |||||
| setTitle: PropTypes.func, | |||||
| setEmploymentType: PropTypes.func, | |||||
| setWorkHour: PropTypes.func, | |||||
| expiredAt: PropTypes.any, | |||||
| setExpiredAt: PropTypes.func, | |||||
| }; | |||||
| export default AddAdModalFirstStage; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { Checkbox, FormControlLabel } from "@mui/material"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { changeIsCheckedAddAdValue } from "../../store/actions/addAdTechnologies/addAdTechnologiesActions"; | |||||
| const AddAdModalSecondStage = ({ | |||||
| onIncrementStage, | |||||
| onDecrementStage, | |||||
| technologies, | |||||
| experience, | |||||
| setExperience, | |||||
| }) => { | |||||
| const dispatch = useDispatch(); | |||||
| const completeStageHandler = () => { | |||||
| const checkedTechnologies = technologies.filter( | |||||
| (x) => x.isChecked === true | |||||
| ); | |||||
| if (checkedTechnologies.length === 0) { | |||||
| return; | |||||
| } | |||||
| onIncrementStage(); | |||||
| }; | |||||
| const handleCheckboxes = (technologyId) => { | |||||
| dispatch(changeIsCheckedAddAdValue(technologyId)); | |||||
| }; | |||||
| return ( | |||||
| <div className="add-ad-modal-stages"> | |||||
| <div> | |||||
| <div className="add-ad-modal-stage-sub-card-title"> | |||||
| <label>Neophodne tehnologije</label> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes-group"> | |||||
| <label>Front-End</label> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Frontend") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes-group"> | |||||
| <label>Back-End</label> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Backend") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes-group"> | |||||
| <label>Other</label> | |||||
| <div className="add-ad-modal-stage-sub-card-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Other") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>Godine iskustva</label> | |||||
| <input | |||||
| type="number" | |||||
| placeholder="ex. 3 godine iskustva" | |||||
| value={experience} | |||||
| onChange={(e) => setExperience(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-actions"> | |||||
| <button | |||||
| className="c-btn c-btn--primary-outlined" | |||||
| onClick={onDecrementStage} | |||||
| > | |||||
| NAZAD | |||||
| </button> | |||||
| <button className="c-btn c-btn--primary" onClick={completeStageHandler}> | |||||
| NASTAVI | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AddAdModalSecondStage.propTypes = { | |||||
| onIncrementStage: PropTypes.func, | |||||
| onDecrementStage: PropTypes.func, | |||||
| technologies: PropTypes.any, | |||||
| experience: PropTypes.any, | |||||
| setExperience: PropTypes.func, | |||||
| }; | |||||
| export default AddAdModalSecondStage; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| const AddAdModalThirdStage = ({ | |||||
| onDecrementStage, | |||||
| keyResponsibilities, | |||||
| setKeyResponsibilities, | |||||
| requirements, | |||||
| setRequirements, | |||||
| whatWeOffer, | |||||
| setWhatWeOffer, | |||||
| onAddAd, | |||||
| }) => { | |||||
| const completeStageHandler = () => { | |||||
| if ( | |||||
| keyResponsibilities.length === 0 || | |||||
| requirements.length === 0 || | |||||
| whatWeOffer.length === 0 | |||||
| ) { | |||||
| return; | |||||
| } | |||||
| onAddAd(); | |||||
| }; | |||||
| return ( | |||||
| <div className="add-ad-modal-stage"> | |||||
| <div> | |||||
| <div className="add-ad-modal-stage-sub-card-third"> | |||||
| <label>Glavna zaduzenja</label> | |||||
| <textarea | |||||
| type="text" | |||||
| placeholder="ex. Working as a React developer on various projects... (Separate every responsibility with | sign)" | |||||
| value={keyResponsibilities} | |||||
| onChange={(e) => setKeyResponsibilities(e.target.value)} | |||||
| rows={5} | |||||
| ></textarea> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card-third"> | |||||
| <label>Uslovi</label> | |||||
| <textarea | |||||
| type="text" | |||||
| placeholder="ex. Good software development fundamentals... (Separate every condition with | sign)" | |||||
| value={requirements} | |||||
| onChange={(e) => setRequirements(e.target.value)} | |||||
| rows={5} | |||||
| ></textarea> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card-third"> | |||||
| <label>Sta nudimo</label> | |||||
| <textarea | |||||
| type="text" | |||||
| placeholder="ex. Full Remote position... (Separate every offer with | sign)" | |||||
| value={whatWeOffer} | |||||
| onChange={(e) => setWhatWeOffer(e.target.value)} | |||||
| rows={5} | |||||
| ></textarea> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad-modal-actions"> | |||||
| <button | |||||
| className="c-btn c-btn--primary-outlined" | |||||
| onClick={onDecrementStage} | |||||
| > | |||||
| NAZAD | |||||
| </button> | |||||
| <button className="c-btn c-btn--primary" onClick={completeStageHandler}> | |||||
| DODAJ OGLAS | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AddAdModalThirdStage.propTypes = { | |||||
| onDecrementStage: PropTypes.func, | |||||
| keyResponsibilities: PropTypes.any, | |||||
| setKeyResponsibilities: PropTypes.func, | |||||
| requirements: PropTypes.any, | |||||
| setRequirements: PropTypes.func, | |||||
| whatWeOffer: PropTypes.any, | |||||
| setWhatWeOffer: PropTypes.func, | |||||
| onAddAd: PropTypes.func, | |||||
| }; | |||||
| export default AddAdModalThirdStage; |
| import { useMediaQuery } from "@mui/material"; | import { useMediaQuery } from "@mui/material"; | ||||
| import { selectArchiveAds } from "../../store/selectors/archiveAdsSelectors"; | import { selectArchiveAds } from "../../store/selectors/archiveAdsSelectors"; | ||||
| import { setArchiveAdsReq } from "../../store/actions/archiveAds/archiveAdsActions"; | import { setArchiveAdsReq } from "../../store/actions/archiveAds/archiveAdsActions"; | ||||
| import noActiveAds from "../../assets/images/no_active_ads.png"; | |||||
| import { setTechnologiesReq } from "../../store/actions/technologies/technologiesActions"; | |||||
| import { selectTechnologies } from "../../store/selectors/technologiesSelectors"; | |||||
| const AdsPage = ({ history }) => { | const AdsPage = ({ history }) => { | ||||
| const theme = useTheme(); | const theme = useTheme(); | ||||
| const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false); | const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false); | ||||
| const [toggleModal, setToggleModal] = useState(false); | const [toggleModal, setToggleModal] = useState(false); | ||||
| const ads = useSelector(selectAds); | const ads = useSelector(selectAds); | ||||
| const technologies = useSelector(selectTechnologies); | |||||
| const archiveAds = useSelector(selectArchiveAds); | const archiveAds = useSelector(selectArchiveAds); | ||||
| const activeAdsSliderRef = useRef(); | const activeAdsSliderRef = useRef(); | ||||
| const archiveAdsSliderRef = useRef(); | const archiveAdsSliderRef = useRef(); | ||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| dispatch(setTechnologiesReq()); | |||||
| dispatch(setAdsReq()); | dispatch(setAdsReq()); | ||||
| dispatch(setArchiveAdsReq()); | dispatch(setArchiveAdsReq()); | ||||
| }, []); | }, []); | ||||
| settings: { | settings: { | ||||
| slidesToShow: 3, | slidesToShow: 3, | ||||
| slidesToScroll: 3, | slidesToScroll: 3, | ||||
| infinite: true, | |||||
| infinite: false, | |||||
| dots: false, | dots: false, | ||||
| }, | }, | ||||
| }, | }, | ||||
| <AdFilters | <AdFilters | ||||
| open={toggleFiltersDrawer} | open={toggleFiltersDrawer} | ||||
| handleClose={handleToggleFiltersDrawer} | handleClose={handleToggleFiltersDrawer} | ||||
| technologies={technologies} | |||||
| /> | /> | ||||
| <AddAdModal open={toggleModal} handleClose={handleToggleModal} /> | <AddAdModal open={toggleModal} handleClose={handleToggleModal} /> | ||||
| <div className="ads"> | <div className="ads"> | ||||
| <button onClick={activeAdsArrowLeftHandler}> | <button onClick={activeAdsArrowLeftHandler}> | ||||
| <img src={arrow_left} alt="arrow-left" /> | <img src={arrow_left} alt="arrow-left" /> | ||||
| </button> | </button> | ||||
| <button onClick={activeAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| {ads.length > 3 && ( | |||||
| <button onClick={activeAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| )} | |||||
| </div> | </div> | ||||
| )} | )} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| {matches && ( | |||||
| {ads && ads.length > 0 && matches && ( | |||||
| <div className="active-ads-ads-arrows"> | <div className="active-ads-ads-arrows"> | ||||
| <button onClick={activeAdsArrowLeftHandler}> | <button onClick={activeAdsArrowLeftHandler}> | ||||
| <img src={arrow_left} alt="arrow-left" /> | <img src={arrow_left} alt="arrow-left" /> | ||||
| </button> | </button> | ||||
| <button onClick={activeAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| {ads.length > 3 && ( | |||||
| <button onClick={activeAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| )} | |||||
| </div> | |||||
| )} | |||||
| {(!ads || ads.length === 0) && ( | |||||
| <div className="active-ads-ads-no-ads"> | |||||
| <img src={noActiveAds} alt="noActiveAds" /> | |||||
| <h1>Nažalost, trenutno nema aktivnih oglasa</h1> | |||||
| <p>Uvek možete dodati novi u samo par jednostavnih koraka</p> | |||||
| <div className="add-ad add-ad-no-ads"> | |||||
| <IconButton | |||||
| className="c-btn c-btn--primary add-ad-btn" | |||||
| onClick={handleToggleModal} | |||||
| > | |||||
| Dodaj Oglas | |||||
| </IconButton> | |||||
| </div> | |||||
| </div> | </div> | ||||
| )} | )} | ||||
| {archiveAds && archiveAds.length > 0 && ( | {archiveAds && archiveAds.length > 0 && ( | ||||
| <button onClick={archiveAdsArrowLeftHandler}> | <button onClick={archiveAdsArrowLeftHandler}> | ||||
| <img src={arrow_left} alt="arrow-left" /> | <img src={arrow_left} alt="arrow-left" /> | ||||
| </button> | </button> | ||||
| <button onClick={archiveAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| {archiveAds.length > 5 && ( | |||||
| <button onClick={archiveAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| )} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| <button onClick={archiveAdsArrowLeftHandler}> | <button onClick={archiveAdsArrowLeftHandler}> | ||||
| <img src={arrow_left} alt="arrow-left" /> | <img src={arrow_left} alt="arrow-left" /> | ||||
| </button> | </button> | ||||
| <button onClick={archiveAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| {archiveAds.length > 5 && ( | |||||
| <button onClick={archiveAdsArrowRightHandler}> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| )} | |||||
| </div> | </div> | ||||
| )} | )} | ||||
| <div className="archive-ads-no-active-ads"></div> | |||||
| </div> | </div> | ||||
| )} | )} | ||||
| </div> | </div> | ||||
| <div className="add-ad"> | |||||
| <IconButton | |||||
| className="c-btn c-btn--primary add-ad-btn" | |||||
| onClick={handleToggleModal} | |||||
| > | |||||
| + Oglas | |||||
| </IconButton> | |||||
| </div> | |||||
| {ads && ads.length > 0 && ( | |||||
| <div className="add-ad"> | |||||
| <IconButton | |||||
| className="c-btn c-btn--primary add-ad-btn" | |||||
| onClick={handleToggleModal} | |||||
| > | |||||
| + Oglas | |||||
| </IconButton> | |||||
| </div> | |||||
| )} | |||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; |
| import { getRequest } from "."; | |||||
| import { getRequest, postRequest } from "."; | |||||
| import apiEndpoints from "./apiEndpoints"; | import apiEndpoints from "./apiEndpoints"; | ||||
| export const getAllAds = () => getRequest(apiEndpoints.ads.allAds); | export const getAllAds = () => getRequest(apiEndpoints.ads.allAds); | ||||
| export const getAllFilteredAds = (payload) => { | |||||
| let technologiesQuery = ""; | |||||
| for (let i = 0; i < payload.technologies.length; i++) { | |||||
| technologiesQuery += `technologies=${payload.technologies[i]}&`; | |||||
| } | |||||
| return getRequest( | |||||
| apiEndpoints.ads.allFilteredAds + | |||||
| `?minExperience=${payload.minExperience}&maxExperience=${payload.maxExperience}&workHour=${payload.workHour}&employmentType=${payload.employmentType}&${technologiesQuery}` | |||||
| ); | |||||
| }; | |||||
| export const getAllArchiveAds = () => | export const getAllArchiveAds = () => | ||||
| getRequest(apiEndpoints.ads.allArchiveAds); | getRequest(apiEndpoints.ads.allArchiveAds); | ||||
| export const getAdDetailsById = (id) => getRequest(`${apiEndpoints.ads.adDetails}/${id}`); | |||||
| export const getAdDetailsById = (id) => | |||||
| getRequest(`${apiEndpoints.ads.adDetails}/${id}`); | |||||
| export const createNewAd = (ad) => postRequest(apiEndpoints.ads.createAd, ad); |
| }, | }, | ||||
| ads: { | ads: { | ||||
| allAds: base + "/ads", | allAds: base + "/ads", | ||||
| createAd: base + "/ads", | |||||
| allFilteredAds: base + "/ads/filtered", | |||||
| allArchiveAds: base + "/ads/archive", | allArchiveAds: base + "/ads/archive", | ||||
| adDetails: base + "/ads/details", | adDetails: base + "/ads/details", | ||||
| }, | }, | ||||
| technologies: { | |||||
| allTechnologies: base + "/technologies", | |||||
| }, | |||||
| comments:{ | comments:{ | ||||
| addComment:base + '/comments' | addComment:base + '/comments' | ||||
| }, | }, |
| import { getRequest } from "."; | |||||
| import apiEndpoints from "./apiEndpoints"; | |||||
| export const getAllTechnologies = () => | |||||
| getRequest(apiEndpoints.technologies.allTechnologies); |
| export const FETCH_ADD_AD_TECHNOLOGIES_REQ = "FETCH_ADD_AD_TECHNOLOGIES_REQ"; | |||||
| export const FETCH_ADD_AD_TECHNOLOGIES_ERR = "FETCH_ADD_AD_TECHNOLOGIES_ERR"; | |||||
| export const FETCH_ADD_AD_TECHNOLOGIES_SUCCESS = "FETCH_ADD_AD_TECHNOLOGIES_SUCCESS"; | |||||
| export const CHANGE_ISCHECKED_VALUE_ADD_AD = "CHANGE_ISCHECKED_VALUE"; |
| import { | |||||
| FETCH_ADD_AD_TECHNOLOGIES_REQ, | |||||
| FETCH_ADD_AD_TECHNOLOGIES_ERR, | |||||
| FETCH_ADD_AD_TECHNOLOGIES_SUCCESS, | |||||
| CHANGE_ISCHECKED_VALUE_ADD_AD, | |||||
| } from "./addAdTechnologiesActionConstants"; | |||||
| export const setTechnologiesAddAdReq = () => ({ | |||||
| type: FETCH_ADD_AD_TECHNOLOGIES_REQ, | |||||
| }); | |||||
| export const setTechnologiesAddAdError = (payload) => ({ | |||||
| type: FETCH_ADD_AD_TECHNOLOGIES_ERR, | |||||
| payload, | |||||
| }); | |||||
| export const setTechnologiesAddAd = (payload) => ({ | |||||
| type: FETCH_ADD_AD_TECHNOLOGIES_SUCCESS, | |||||
| payload, | |||||
| }); | |||||
| export const changeIsCheckedAddAdValue = (payload) => ({ | |||||
| type: CHANGE_ISCHECKED_VALUE_ADD_AD, | |||||
| payload, | |||||
| }); | |||||
| FETCH_ADS_REQ, | FETCH_ADS_REQ, | ||||
| FETCH_ADS_ERR, | FETCH_ADS_ERR, | ||||
| FETCH_ADS_SUCCESS, | FETCH_ADS_SUCCESS, | ||||
| FETCH_FILTERED_ADS_REQ, | |||||
| FETCH_FILTERED_ADS_ERR, | |||||
| FETCH_FILTERED_ADS_SUCCESS, | |||||
| } from "./adsActionConstants"; | } from "./adsActionConstants"; | ||||
| export const setAdsReq = () => ({ | export const setAdsReq = () => ({ | ||||
| type: FETCH_ADS_SUCCESS, | type: FETCH_ADS_SUCCESS, | ||||
| payload, | payload, | ||||
| }); | }); | ||||
| export const setFilteredAdsReq = (payload) => ({ | |||||
| type: FETCH_FILTERED_ADS_REQ, | |||||
| payload, | |||||
| }); | |||||
| export const setFilteredAdsError = (payload) => ({ | |||||
| type: FETCH_FILTERED_ADS_ERR, | |||||
| payload, | |||||
| }); | |||||
| export const setFilteredAds = (payload) => ({ | |||||
| type: FETCH_FILTERED_ADS_SUCCESS, | |||||
| payload, | |||||
| }); |
| export const FETCH_ADS_REQ = 'FETCH_ADS_REQ'; | export const FETCH_ADS_REQ = 'FETCH_ADS_REQ'; | ||||
| export const FETCH_ADS_ERR = 'FETCH_ADS_ERR'; | export const FETCH_ADS_ERR = 'FETCH_ADS_ERR'; | ||||
| export const FETCH_ADS_SUCCESS = 'FETCH_ADS_SUCCESS'; | |||||
| export const FETCH_ADS_SUCCESS = 'FETCH_ADS_SUCCESS'; | |||||
| export const FETCH_FILTERED_ADS_REQ = 'FETCH_FILTERED_ADS_REQ'; | |||||
| export const FETCH_FILTERED_ADS_ERR = 'FETCH_FILTERED_ADS_ERR'; | |||||
| export const FETCH_FILTERED_ADS_SUCCESS = 'FETCH_FILTERED_ADS_SUCCESS'; |
| import { | |||||
| createErrorType, | |||||
| createFetchType, | |||||
| createLoadingType, | |||||
| createSuccessType, | |||||
| } from "../actionHelpers"; | |||||
| const CREATE_AD_SCOPE = "CREATE_AD"; | |||||
| export const CREATE_AD_REQ = createFetchType(CREATE_AD_SCOPE); | |||||
| export const CREATE_AD_ERR = createErrorType(CREATE_AD_SCOPE); | |||||
| export const CREATE_AD_SUCCESS = createSuccessType(CREATE_AD_SCOPE); | |||||
| export const CREATE_AD_LOADING = createLoadingType(CREATE_AD_SCOPE); | |||||
| import { | |||||
| CREATE_AD_ERR, | |||||
| CREATE_AD_REQ, | |||||
| CREATE_AD_SUCCESS, | |||||
| } from "./createAdActionConstants"; | |||||
| export const setCreateAdReq = (payload) => ({ | |||||
| type: CREATE_AD_REQ, | |||||
| payload, | |||||
| }); | |||||
| export const setCreateAdError = (payload) => ({ | |||||
| type: CREATE_AD_ERR, | |||||
| payload, | |||||
| }); | |||||
| export const setCreateAd = (payload) => ({ | |||||
| type: CREATE_AD_SUCCESS, | |||||
| payload, | |||||
| }); | |||||
| export const FETCH_TECHNOLOGIES_REQ = "FETCH_TECHNOLOGIES_REQ"; | |||||
| export const FETCH_TECHNOLOGIES_ERR = "FETCH_TECHNOLOGIES_ERR"; | |||||
| export const FETCH_TECHNOLOGIES_SUCCESS = "FETCH_TECHNOLOGIES_SUCCESS"; | |||||
| export const CHANGE_ISCHECKED_VALUE = "CHANGE_ISCHECKED_VALUE"; |
| import { | |||||
| FETCH_TECHNOLOGIES_ERR, | |||||
| FETCH_TECHNOLOGIES_SUCCESS, | |||||
| FETCH_TECHNOLOGIES_REQ, | |||||
| CHANGE_ISCHECKED_VALUE | |||||
| } from "./technologiesActionConstants"; | |||||
| export const setTechnologiesReq = () => ({ | |||||
| type: FETCH_TECHNOLOGIES_REQ, | |||||
| }); | |||||
| export const setTechnologiesError = (payload) => ({ | |||||
| type: FETCH_TECHNOLOGIES_ERR, | |||||
| payload, | |||||
| }); | |||||
| export const setTechnologies = (payload) => ({ | |||||
| type: FETCH_TECHNOLOGIES_SUCCESS, | |||||
| payload, | |||||
| }); | |||||
| export const changeIsCheckedValue = (payload) => ({ | |||||
| type: CHANGE_ISCHECKED_VALUE, | |||||
| payload, | |||||
| }); |
| import { | import { | ||||
| FETCH_ADS_ERR, | FETCH_ADS_ERR, | ||||
| FETCH_ADS_SUCCESS, | FETCH_ADS_SUCCESS, | ||||
| FETCH_FILTERED_ADS_ERR, | |||||
| FETCH_FILTERED_ADS_SUCCESS, | |||||
| } from "../../actions/ads/adsActionConstants"; | } from "../../actions/ads/adsActionConstants"; | ||||
| import createReducer from "../../utils/createReducer"; | import createReducer from "../../utils/createReducer"; | ||||
| { | { | ||||
| [FETCH_ADS_SUCCESS]: setStateAds, | [FETCH_ADS_SUCCESS]: setStateAds, | ||||
| [FETCH_ADS_ERR]: setAdsErrorMessage, | [FETCH_ADS_ERR]: setAdsErrorMessage, | ||||
| [FETCH_FILTERED_ADS_SUCCESS]: setStateFilteredAds, | |||||
| [FETCH_FILTERED_ADS_ERR]: setFilteredAdsErrorMessage, | |||||
| }, | }, | ||||
| initialState | initialState | ||||
| ); | ); | ||||
| errorMessage: action.payload, | errorMessage: action.payload, | ||||
| }; | }; | ||||
| } | } | ||||
| function setStateFilteredAds(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| ads: action.payload, | |||||
| }; | |||||
| } | |||||
| function setFilteredAdsErrorMessage(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| errorMessage: action.payload, | |||||
| }; | |||||
| } |
| import { | |||||
| CREATE_AD_SUCCESS, | |||||
| CREATE_AD_ERR, | |||||
| } from "../../actions/createAd/createAdActionConstants"; | |||||
| import createReducer from "../../utils/createReducer"; | |||||
| const initialState = { | |||||
| ad: null, | |||||
| errorMessage: "", | |||||
| }; | |||||
| export default createReducer( | |||||
| { | |||||
| [CREATE_AD_SUCCESS]: setStateCreateAd, | |||||
| [CREATE_AD_ERR]: setStateErrorMessage, | |||||
| }, | |||||
| initialState | |||||
| ); | |||||
| function setStateCreateAd(state, action) { | |||||
| return { ...state, ad: action.payload }; | |||||
| } | |||||
| function setStateErrorMessage(state, action) { | |||||
| return { ...state, errorMessage: action.payload }; | |||||
| } |
| import { combineReducers } from 'redux'; | |||||
| import loginReducer from './login/loginReducer'; | |||||
| import loadingReducer from './loading/loadingReducer'; | |||||
| import userReducer from './user/userReducer'; | |||||
| import randomDataReducer from './randomData/randomDataReducer'; | |||||
| import usersReducer from './user/usersReducer'; | |||||
| import candidateReducer from './candidate/candidateReducer'; | |||||
| import { combineReducers } from "redux"; | |||||
| import loginReducer from "./login/loginReducer"; | |||||
| import loadingReducer from "./loading/loadingReducer"; | |||||
| import userReducer from "./user/userReducer"; | |||||
| import randomDataReducer from "./randomData/randomDataReducer"; | |||||
| import usersReducer from "./user/usersReducer"; | |||||
| import candidateReducer from "./candidate/candidateReducer"; | |||||
| import adsReducer from "./ad/adsReducer"; | import adsReducer from "./ad/adsReducer"; | ||||
| import adReducer from "./ad/adReducer"; | import adReducer from "./ad/adReducer"; | ||||
| import archiveAdsReducer from "./ad/archiveAdsReducer"; | import archiveAdsReducer from "./ad/archiveAdsReducer"; | ||||
| import candidatesReducer from "./candidates/candidatesReducer"; | import candidatesReducer from "./candidates/candidatesReducer"; | ||||
| import processesReducer from './processes/processesReducer'; | |||||
| import technologiesReducer from "./technology/technologiesReducer"; | |||||
| import addAddTechnologiesReducer from "./technology/addAddTechnologiesReducer"; | |||||
| import createAdReducer from "./ad/createAdReducer"; | |||||
| import processesReducer from "./processes/processesReducer"; | |||||
| import processReducer from "./processes/processReducer"; | import processReducer from "./processes/processReducer"; | ||||
| import applicantWithProcessesReducer from "./processes/applicantWithProcessesReducer"; | import applicantWithProcessesReducer from "./processes/applicantWithProcessesReducer"; | ||||
| import userDetailsReducer from './user/userDetailsReducer'; | |||||
| import inviteUserReducer from './user/inviteUserReducer'; | |||||
| import userDetailsReducer from "./user/userDetailsReducer"; | |||||
| import inviteUserReducer from "./user/inviteUserReducer"; | |||||
| export default combineReducers({ | export default combineReducers({ | ||||
| login: loginReducer, | login: loginReducer, | ||||
| loading: loadingReducer, | loading: loadingReducer, | ||||
| randomData: randomDataReducer, | randomData: randomDataReducer, | ||||
| users: usersReducer, | users: usersReducer, | ||||
| candidate:candidateReducer, | |||||
| candidate: candidateReducer, | |||||
| ads: adsReducer, | ads: adsReducer, | ||||
| ad: adReducer, | ad: adReducer, | ||||
| archiveAds: archiveAdsReducer, | archiveAds: archiveAdsReducer, | ||||
| technologies: technologiesReducer, | |||||
| addAdTechnologies: addAddTechnologiesReducer, | |||||
| createAd: createAdReducer, | |||||
| candidates: candidatesReducer, | candidates: candidatesReducer, | ||||
| processes: processesReducer, | processes: processesReducer, | ||||
| process: processReducer, | process: processReducer, | ||||
| applicant: applicantWithProcessesReducer, | applicant: applicantWithProcessesReducer, | ||||
| userDetails: userDetailsReducer, | userDetails: userDetailsReducer, | ||||
| invite: inviteUserReducer | |||||
| invite: inviteUserReducer, | |||||
| }); | }); |
| import createReducer from "../../utils/createReducer"; | |||||
| import { | |||||
| FETCH_ADD_AD_TECHNOLOGIES_ERR, | |||||
| FETCH_ADD_AD_TECHNOLOGIES_SUCCESS, | |||||
| CHANGE_ISCHECKED_VALUE_ADD_AD, | |||||
| } from "../../actions/addAdTechnologies/addAdTechnologiesActionConstants"; | |||||
| const initialState = { | |||||
| technologies: [], | |||||
| errorMessage: "", | |||||
| }; | |||||
| export default createReducer( | |||||
| { | |||||
| [FETCH_ADD_AD_TECHNOLOGIES_SUCCESS]: setStateTechnologiesAddAd, | |||||
| [FETCH_ADD_AD_TECHNOLOGIES_ERR]: setStateAddAdErrorMessage, | |||||
| [CHANGE_ISCHECKED_VALUE_ADD_AD]: setIsCheckedTechnologyAddAd, | |||||
| }, | |||||
| initialState | |||||
| ); | |||||
| function setStateTechnologiesAddAd(state, action) { | |||||
| return { ...state, technologies: action.payload }; | |||||
| } | |||||
| function setStateAddAdErrorMessage(state, action) { | |||||
| return { ...state, errorMessage: action.payload }; | |||||
| } | |||||
| function setIsCheckedTechnologyAddAd(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| technologies: state.technologies.map((tech) => | |||||
| tech.technologyId === action.payload | |||||
| ? { ...tech, isChecked: !tech.isChecked } | |||||
| : tech | |||||
| ), | |||||
| }; | |||||
| } |
| import createReducer from "../../utils/createReducer"; | |||||
| import { | |||||
| FETCH_TECHNOLOGIES_SUCCESS, | |||||
| FETCH_TECHNOLOGIES_ERR, | |||||
| CHANGE_ISCHECKED_VALUE, | |||||
| } from "../../actions/technologies/technologiesActionConstants"; | |||||
| const initialState = { | |||||
| technologies: [], | |||||
| errorMessage: "", | |||||
| }; | |||||
| export default createReducer( | |||||
| { | |||||
| [FETCH_TECHNOLOGIES_SUCCESS]: setStateTechnologies, | |||||
| [FETCH_TECHNOLOGIES_ERR]: setStateErrorMessage, | |||||
| [CHANGE_ISCHECKED_VALUE]: setIsCheckedTechnology, | |||||
| }, | |||||
| initialState | |||||
| ); | |||||
| function setStateTechnologies(state, action) { | |||||
| return { ...state, technologies: action.payload }; | |||||
| } | |||||
| function setStateErrorMessage(state, action) { | |||||
| return { ...state, errorMessage: action.payload }; | |||||
| } | |||||
| function setIsCheckedTechnology(state, action) { | |||||
| const tmpIndex = state.technologies.findIndex( | |||||
| (x) => x.name === action.payload | |||||
| ); | |||||
| if (tmpIndex === -1) { | |||||
| return state; | |||||
| } | |||||
| return { | |||||
| ...state, | |||||
| technologies: state.technologies.map((tech, index) => | |||||
| tmpIndex === index ? { ...tech, isChecked: !tech.isChecked } : tech | |||||
| ), | |||||
| }; | |||||
| } |
| getAllAds, | getAllAds, | ||||
| getAdDetailsById, | getAdDetailsById, | ||||
| getAllArchiveAds, | getAllArchiveAds, | ||||
| getAllFilteredAds, | |||||
| createNewAd, | |||||
| } from "../../request/adsRequest"; | } from "../../request/adsRequest"; | ||||
| import { setAds, setAdsError } from "../actions/ads/adsAction"; | |||||
| import { | |||||
| setAds, | |||||
| setAdsError, | |||||
| setFilteredAds, | |||||
| setFilteredAdsError, | |||||
| } from "../actions/ads/adsAction"; | |||||
| import { setAd, setAdError } from "../actions/ad/adActions"; | import { setAd, setAdError } from "../actions/ad/adActions"; | ||||
| import { | import { | ||||
| setArchiveAds, | setArchiveAds, | ||||
| setArchiveAdsError, | setArchiveAdsError, | ||||
| } from "../actions/archiveAds/archiveAdsActions"; | } from "../actions/archiveAds/archiveAdsActions"; | ||||
| import { FETCH_ADS_REQ } from "../actions/ads/adsActionConstants"; | import { FETCH_ADS_REQ } from "../actions/ads/adsActionConstants"; | ||||
| import { FETCH_FILTERED_ADS_REQ } from "../actions/ads/adsActionConstants"; | |||||
| import { FETCH_AD_REQ } from "../actions/ad/adActionConstants"; | import { FETCH_AD_REQ } from "../actions/ad/adActionConstants"; | ||||
| import { FETCH_ARCHIVE_ADS_REQ } from "../actions/archiveAds/archiveAdsActionConstants"; | import { FETCH_ARCHIVE_ADS_REQ } from "../actions/archiveAds/archiveAdsActionConstants"; | ||||
| import { CREATE_AD_REQ } from "../actions/createAd/createAdActionConstants"; | |||||
| import { | |||||
| setCreateAd, | |||||
| setCreateAdError, | |||||
| } from "../actions/createAd/createAdActions"; | |||||
| export function* getAds() { | export function* getAds() { | ||||
| try { | try { | ||||
| } | } | ||||
| } | } | ||||
| export function* getFilteredAds({ payload }) { | |||||
| try { | |||||
| const result = yield call(getAllFilteredAds, payload); | |||||
| yield put(setFilteredAds(result.data)); | |||||
| } catch (error) { | |||||
| yield put(setFilteredAdsError(error)); | |||||
| } | |||||
| } | |||||
| export function* getAd({ payload }) { | export function* getAd({ payload }) { | ||||
| try { | try { | ||||
| const result = yield call(getAdDetailsById, payload.id); | const result = yield call(getAdDetailsById, payload.id); | ||||
| } | } | ||||
| } | } | ||||
| export function* createAd({ payload }) { | |||||
| try { | |||||
| const result = yield call(createNewAd, payload); | |||||
| const ad = result.data; | |||||
| yield put(setCreateAd(ad)); | |||||
| } catch (error) { | |||||
| yield put(setCreateAdError(error)); | |||||
| } | |||||
| } | |||||
| export default function* adsSaga() { | export default function* adsSaga() { | ||||
| yield all([ | yield all([ | ||||
| takeLatest(FETCH_ADS_REQ, getAds), | takeLatest(FETCH_ADS_REQ, getAds), | ||||
| takeLatest(FETCH_FILTERED_ADS_REQ, getFilteredAds), | |||||
| takeLatest(FETCH_AD_REQ, getAd), | takeLatest(FETCH_AD_REQ, getAd), | ||||
| takeLatest(FETCH_ARCHIVE_ADS_REQ, getArchiveAds), | takeLatest(FETCH_ARCHIVE_ADS_REQ, getArchiveAds), | ||||
| takeLatest(CREATE_AD_REQ, createAd), | |||||
| ]); | ]); | ||||
| } | } |
| import adsSaga from "./adsSaga"; | import adsSaga from "./adsSaga"; | ||||
| import candidatesSaga from './candidatesSaga'; | import candidatesSaga from './candidatesSaga'; | ||||
| import loginSaga from "./loginSaga"; | import loginSaga from "./loginSaga"; | ||||
| import technologiesSaga from "./technologiesSaga"; | |||||
| import usersSaga from "./usersSaga"; | import usersSaga from "./usersSaga"; | ||||
| import processesSaga from "./processSaga"; | import processesSaga from "./processSaga"; | ||||
| loginSaga(), | loginSaga(), | ||||
| usersSaga(), | usersSaga(), | ||||
| adsSaga(), | adsSaga(), | ||||
| technologiesSaga(), | |||||
| candidatesSaga(), | candidatesSaga(), | ||||
| processesSaga(), | processesSaga(), | ||||
| ]); | ]); |
| import { all, call, put, takeLatest } from "redux-saga/effects"; | |||||
| import { getAllTechnologies } from "../../request/technologiesRequest"; | |||||
| import { FETCH_ADD_AD_TECHNOLOGIES_REQ } from "../actions/addAdTechnologies/addAdTechnologiesActionConstants"; | |||||
| import { setTechnologiesAddAd } from "../actions/addAdTechnologies/addAdTechnologiesActions"; | |||||
| import { FETCH_TECHNOLOGIES_REQ } from "../actions/technologies/technologiesActionConstants"; | |||||
| import { | |||||
| setTechnologies, | |||||
| setTechnologiesError, | |||||
| } from "../actions/technologies/technologiesActions"; | |||||
| export function* getTechnologies() { | |||||
| try { | |||||
| const result = yield call(getAllTechnologies); | |||||
| const resultData = result.data.map((res) => ({ ...res, isChecked: false })); | |||||
| yield put(setTechnologies(resultData)); | |||||
| } catch (error) { | |||||
| yield put(setTechnologiesError(error)); | |||||
| } | |||||
| } | |||||
| export function* getTechnologiesAddAd() { | |||||
| try { | |||||
| const result = yield call(getAllTechnologies); | |||||
| const resultData = result.data.map((res) => ({ ...res, isChecked: false })); | |||||
| yield put(setTechnologiesAddAd(resultData)); | |||||
| } catch (error) { | |||||
| yield put(setTechnologiesError(error)); | |||||
| } | |||||
| } | |||||
| export default function* technologiesSaga() { | |||||
| yield all([ | |||||
| takeLatest(FETCH_TECHNOLOGIES_REQ, getTechnologies), | |||||
| takeLatest(FETCH_ADD_AD_TECHNOLOGIES_REQ, getTechnologiesAddAd), | |||||
| ]); | |||||
| } |
| import { createSelector } from "@reduxjs/toolkit"; | |||||
| export const technologiesSelector = (state) => state.technologies; | |||||
| export const selectTechnologies = createSelector( | |||||
| technologiesSelector, | |||||
| (state) => state.technologies | |||||
| ); | |||||
| export const selectTechnologiesError = createSelector( | |||||
| technologiesSelector, | |||||
| (state) => state.errorMessage | |||||
| ); |