| @@ -33,6 +33,7 @@ | |||
| "react-dom": "^17.0.2", | |||
| "react-helmet-async": "^1.0.9", | |||
| "react-i18next": "^11.10.0", | |||
| "react-mentions": "^4.4.7", | |||
| "react-redux": "^7.2.4", | |||
| "react-router-dom": "^5.2.0", | |||
| "react-scripts": "4.0.3", | |||
| @@ -18516,6 +18517,29 @@ | |||
| "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", | |||
| "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" | |||
| }, | |||
| "node_modules/react-mentions": { | |||
| "version": "4.4.7", | |||
| "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz", | |||
| "integrity": "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==", | |||
| "dependencies": { | |||
| "@babel/runtime": "7.4.5", | |||
| "invariant": "^2.2.4", | |||
| "prop-types": "^15.5.8", | |||
| "substyle": "^9.1.0" | |||
| }, | |||
| "peerDependencies": { | |||
| "react": ">=16.8.3", | |||
| "react-dom": ">=16.8.3" | |||
| } | |||
| }, | |||
| "node_modules/react-mentions/node_modules/@babel/runtime": { | |||
| "version": "7.4.5", | |||
| "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", | |||
| "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", | |||
| "dependencies": { | |||
| "regenerator-runtime": "^0.13.2" | |||
| } | |||
| }, | |||
| "node_modules/react-redux": { | |||
| "version": "7.2.9", | |||
| "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", | |||
| @@ -21188,6 +21212,18 @@ | |||
| "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", | |||
| "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" | |||
| }, | |||
| "node_modules/substyle": { | |||
| "version": "9.4.1", | |||
| "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", | |||
| "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", | |||
| "dependencies": { | |||
| "@babel/runtime": "^7.3.4", | |||
| "invariant": "^2.2.4" | |||
| }, | |||
| "peerDependencies": { | |||
| "react": ">=16.8.3" | |||
| } | |||
| }, | |||
| "node_modules/supports-color": { | |||
| "version": "5.5.0", | |||
| "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", | |||
| @@ -38686,6 +38722,27 @@ | |||
| "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", | |||
| "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" | |||
| }, | |||
| "react-mentions": { | |||
| "version": "4.4.7", | |||
| "resolved": "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz", | |||
| "integrity": "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==", | |||
| "requires": { | |||
| "@babel/runtime": "7.4.5", | |||
| "invariant": "^2.2.4", | |||
| "prop-types": "^15.5.8", | |||
| "substyle": "^9.1.0" | |||
| }, | |||
| "dependencies": { | |||
| "@babel/runtime": { | |||
| "version": "7.4.5", | |||
| "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", | |||
| "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", | |||
| "requires": { | |||
| "regenerator-runtime": "^0.13.2" | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| "react-redux": { | |||
| "version": "7.2.9", | |||
| "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", | |||
| @@ -40831,6 +40888,15 @@ | |||
| "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", | |||
| "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" | |||
| }, | |||
| "substyle": { | |||
| "version": "9.4.1", | |||
| "resolved": "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz", | |||
| "integrity": "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==", | |||
| "requires": { | |||
| "@babel/runtime": "^7.3.4", | |||
| "invariant": "^2.2.4" | |||
| } | |||
| }, | |||
| "supports-color": { | |||
| "version": "5.5.0", | |||
| "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", | |||
| @@ -28,6 +28,7 @@ | |||
| "react-dom": "^17.0.2", | |||
| "react-helmet-async": "^1.0.9", | |||
| "react-i18next": "^11.10.0", | |||
| "react-mentions": "^4.4.7", | |||
| "react-redux": "^7.2.4", | |||
| "react-router-dom": "^5.2.0", | |||
| "react-scripts": "4.0.3", | |||
| @@ -6,16 +6,17 @@ import history from "./store/utils/history"; | |||
| import MainContainer from "./components/Section/MainContainer"; | |||
| import AppRoutes from "./AppRoutes"; | |||
| import { useDispatch } from "react-redux"; | |||
| import {refreshUserToken} from "./store/actions/login/loginActions"; | |||
| import { refreshUserToken } from "./store/actions/login/loginActions"; | |||
| import { BASE_PAGE } from "./constants/pages"; | |||
| const App = () => { | |||
| const dispatch = useDispatch() | |||
| const dispatch = useDispatch(); | |||
| useEffect(() => { | |||
| if(history.location.pathname === BASE_PAGE) | |||
| if (history.location.pathname === BASE_PAGE) { | |||
| return; | |||
| dispatch(refreshUserToken()) | |||
| },[]) | |||
| } | |||
| dispatch(refreshUserToken()); | |||
| }, []); | |||
| return ( | |||
| <> | |||
| @@ -11,7 +11,8 @@ import { | |||
| BASE_PAGE, | |||
| RESET_PASSWORD_PAGE, | |||
| USERS_PAGE, | |||
| CANDIDATES_PAGE | |||
| CANDIDATES_PAGE, | |||
| CANDIDATES_DETAILS_PAGE | |||
| } from "./constants/pages"; | |||
| // import LoginPage from './pages/LoginPage/LoginPage'; | |||
| @@ -28,6 +29,7 @@ import ForgotPasswordConfirmationPage from "./pages/ForgotPasswordPage/ForgotPas | |||
| import ResetPasswordPage from "./pages/ForgotPasswordPage/ResetPasswordPageMUI"; | |||
| import UsersPage from "./pages/UsersPage/UsersPage"; | |||
| import CandidatesPage from './pages/CandidatesPage/CandidatesPage' | |||
| import CandidateDetailsPage from "./pages/CandidateDetailsPage/CandidateDetailsPage"; | |||
| const AppRoutes = () => ( | |||
| <Switch> | |||
| @@ -45,6 +47,7 @@ const AppRoutes = () => ( | |||
| <PrivateRoute exact path={ADS_PAGE} component={AdsPage} /> | |||
| <PrivateRoute exact path={USERS_PAGE} component={UsersPage} /> | |||
| <PrivateRoute exact path={CANDIDATES_PAGE} component={CandidatesPage} /> | |||
| <PrivateRoute exact path={CANDIDATES_DETAILS_PAGE} component={CandidateDetailsPage} /> | |||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | |||
| </Switch> | |||
| ); | |||
| @@ -0,0 +1,486 @@ | |||
| .main-candidate-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .top-candidate-container { | |||
| display: flex; | |||
| width: 100%; | |||
| justify-content: space-between; | |||
| } | |||
| .candidate-header { | |||
| height: 36px; | |||
| font-family: Source Sans Pro; | |||
| font-size: 36px; | |||
| font-weight: 600; | |||
| line-height: 36px; | |||
| letter-spacing: 0.02em; | |||
| text-align: left; | |||
| color: #272727; | |||
| } | |||
| .separation-line { | |||
| margin-left: 5px; | |||
| margin-right: 5px; | |||
| font-size: 20px; | |||
| align-self: flex-end; | |||
| } | |||
| .candidate-lower-header { | |||
| font-family: Source Sans Pro; | |||
| font-size: 24px; | |||
| font-weight: 600; | |||
| line-height: 32px; | |||
| letter-spacing: 0.02em; | |||
| text-align: left; | |||
| color: #226cb0; | |||
| align-self: flex-end; | |||
| } | |||
| .candidate-option-container { | |||
| display: flex; | |||
| height: 38px; | |||
| } | |||
| .content-candidate-container { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| margin-top: 14px; | |||
| } | |||
| .technologies-candidate-container { | |||
| display: flex; | |||
| margin-top: 18px; | |||
| } | |||
| .technology-candidate-card { | |||
| display: flex; | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| align-items: center; | |||
| padding: 9px; | |||
| gap: 10px; | |||
| background: #ffffff; | |||
| border: 1px solid #e4e4e4; | |||
| border-radius: 9px; | |||
| } | |||
| .technology-candidate-card:not(:last-child) { | |||
| margin-right: 18px; | |||
| } | |||
| .comment-container { | |||
| width: 612px; | |||
| height: 404px; | |||
| background: #ffffff; | |||
| border: 1px solid #e4e4e4; | |||
| border-radius: 12px; | |||
| margin-top: 16px; | |||
| } | |||
| .candidate-informations-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .candidate-informations-sub-container { | |||
| margin-top: 36px; | |||
| } | |||
| .informations-candidate-header { | |||
| font-family: "Source Sans Pro"; | |||
| font-style: normal; | |||
| font-weight: 600; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| color: #272727; | |||
| } | |||
| .candidate-property-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .candidate-property { | |||
| margin-top: 18px; | |||
| font-family: Source Sans Pro; | |||
| font-size: 16px; | |||
| font-weight: 400; | |||
| line-height: 20px; | |||
| letter-spacing: 0em; | |||
| } | |||
| .candidate-property-value { | |||
| @extend .candidate-property; | |||
| color: #1e92d0; | |||
| } | |||
| .candidate-informations-sub-container { | |||
| display: flex; | |||
| } | |||
| .comment-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| padding-left: 36px; | |||
| padding-right: 36px; | |||
| padding-top: 36px; | |||
| } | |||
| .comment-sub-container { | |||
| display: flex; | |||
| align-items: center; | |||
| } | |||
| .comment-sub-container:not(:first-child) { | |||
| margin-top: 36px; | |||
| } | |||
| .comment-sender { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| width: 40px; | |||
| height: 40px; | |||
| border-radius: 50%; | |||
| box-sizing: border-box; | |||
| border: 1px solid; | |||
| border-color: #226cb0; | |||
| } | |||
| .comment-sender p { | |||
| color: #226cb0; | |||
| } | |||
| .comment-message { | |||
| display: flex; | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| align-items: flex-end; | |||
| padding: 9px; | |||
| gap: 9px; | |||
| height: 62px; | |||
| background: #f4f4f4; | |||
| border-radius: 12px; | |||
| margin-left: 18px; | |||
| } | |||
| .comment-message-content { | |||
| align-self: flex-start; | |||
| height: 20px; | |||
| font-family: "Source Sans Pro"; | |||
| font-style: normal; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| } | |||
| .comment-message-date { | |||
| align-self: flex-end; | |||
| height: 15px; | |||
| font-family: "Source Sans Pro"; | |||
| font-style: normal; | |||
| font-weight: 400; | |||
| font-size: 12px; | |||
| line-height: 15px; | |||
| color: #272727; | |||
| } | |||
| .comment-separation-line { | |||
| width: 100%; | |||
| height: 0px; | |||
| border: 1px solid #e4e4e4; | |||
| background: #e4e4e4; | |||
| } | |||
| .send-comment-container { | |||
| margin-top: 18px; | |||
| } | |||
| .send-comment-container p { | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| color: #9d9d9d; | |||
| } | |||
| .send-comment-sub-container { | |||
| display: flex; | |||
| margin-top: 9px; | |||
| height: 56px; | |||
| margin-bottom: 36px; | |||
| } | |||
| .comment-send-btn { | |||
| display: flex; | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| align-items: center; | |||
| padding: 18px 36px; | |||
| gap: 10px; | |||
| background: #ffffff; | |||
| border: 1px solid #226cb0; | |||
| border-radius: 9px; | |||
| border: 1px solid #226cb0; | |||
| width: 156px; | |||
| margin-left: 18px; | |||
| } | |||
| .comment-send-btn:hover { | |||
| cursor: pointer; | |||
| } | |||
| .comment-send-btn p { | |||
| width: 62px; | |||
| height: 15px; | |||
| font-family: "Source Sans Pro"; | |||
| font-style: normal; | |||
| font-weight: 600; | |||
| font-size: 12px; | |||
| line-height: 15px; | |||
| letter-spacing: 0.04em; | |||
| text-transform: uppercase; | |||
| color: #226cb0; | |||
| flex: none; | |||
| order: 1; | |||
| flex-grow: 0; | |||
| } | |||
| .comment-send-btn img { | |||
| width: 12px; | |||
| height: 12px; | |||
| } | |||
| .candidate-users { | |||
| background-color: #f4f4f4; | |||
| } | |||
| .candidate-user { | |||
| color: #226cb0; | |||
| } | |||
| .applicant-ads-container { | |||
| margin-top: 36px; | |||
| } | |||
| .applicant-ads-container > p { | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 600; | |||
| font-size: 24px; | |||
| line-height: 32px; | |||
| letter-spacing: 0.02em; | |||
| color: #272727; | |||
| } | |||
| .applicant-ads-sub-container { | |||
| margin-top: 18px; | |||
| } | |||
| .applicant-add { | |||
| display: flex; | |||
| flex-direction: column; | |||
| align-items: center; | |||
| padding: 36px; | |||
| gap: 18px; | |||
| background: #ffffff; | |||
| border: 1px solid #e4e4e4; | |||
| border-radius: 12px; | |||
| width: 247px; | |||
| height: 238px; | |||
| } | |||
| .applicant-add-date { | |||
| font-family: Source Sans Pro; | |||
| font-size: 12px; | |||
| font-weight: 400; | |||
| line-height: 15px; | |||
| letter-spacing: 0em; | |||
| } | |||
| .applicant-add-title { | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 600; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| color: #226cb0; | |||
| } | |||
| .applicant-add-site { | |||
| display: flex; | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| align-items: center; | |||
| background: #ffffff; | |||
| padding: 5px; | |||
| border: 1px solid #e4e4e4; | |||
| border-radius: 8px; | |||
| font-size: 16px; | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 400; | |||
| color: #272727; | |||
| } | |||
| .applicant-ads-buttons-container { | |||
| display: flex; | |||
| align-self: flex-end; | |||
| align-items: center; | |||
| margin-bottom: 54px; | |||
| margin-top: 18px; | |||
| } | |||
| .applicant-cv-button { | |||
| display: flex; | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| align-items: center; | |||
| padding: 18px 72px; | |||
| gap: 10px; | |||
| background: #226cb0; | |||
| border-radius: 9px; | |||
| width: 212px; | |||
| height: 51px; | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 600; | |||
| font-size: 12px; | |||
| line-height: 15px; | |||
| letter-spacing: 0.04em; | |||
| text-transform: uppercase; | |||
| color: #ffffff; | |||
| } | |||
| .applicant-ads-back-button { | |||
| margin-right: 36px; | |||
| font-family: "Source Sans Pro"; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| text-decoration-line: underline; | |||
| color: #226cb0; | |||
| } | |||
| .tagStyle { | |||
| color: #226cb0; | |||
| font-family: Source Sans Pro; | |||
| font-size: 16px; | |||
| font-weight: 600; | |||
| line-height: 20px; | |||
| letter-spacing: 0em; | |||
| } | |||
| .comment-input { | |||
| @extend .tagStyle; | |||
| width: 368px; | |||
| } | |||
| .comment-input ::placeholder { | |||
| width: 139px; | |||
| height: 20px; | |||
| font-family: "Source Sans Pro"; | |||
| font-style: italic; | |||
| font-weight: 400; | |||
| font-size: 16px; | |||
| line-height: 20px; | |||
| color: #9d9d9d; | |||
| flex: none; | |||
| order: 0; | |||
| flex-grow: 0; | |||
| } | |||
| .comment-input-list{ | |||
| @extend .tagStyle; | |||
| } | |||
| @media only screen and (max-width: 930px) { | |||
| .comment-container { | |||
| width:500px; | |||
| } | |||
| } | |||
| @media only screen and (max-width: 820px) { | |||
| .comment-container { | |||
| width:400px; | |||
| }; | |||
| .comment-send-btn{ | |||
| width: 130; | |||
| padding: 12px 28px; | |||
| }; | |||
| .send-comment-sub-container{ | |||
| height: 45px; | |||
| margin-bottom: 20px | |||
| }; | |||
| .comment-input ::placeholder{ | |||
| font-size: 14px; | |||
| line-height: 18px; | |||
| padding-top:2px; | |||
| } | |||
| } | |||
| @media only screen and (max-width: 700px) { | |||
| .comment-container { | |||
| width:380px; | |||
| } | |||
| .comment-send-btn{ | |||
| width: 110; | |||
| padding: 10px 20px; | |||
| }; | |||
| } | |||
| @media only screen and (max-width:680px) { | |||
| .content-candidate-container{ | |||
| flex-direction: column; | |||
| } | |||
| .comment-container { | |||
| margin-top: 30px; | |||
| } | |||
| } | |||
| @media only screen and (max-width:540px) { | |||
| .candidate-header{ | |||
| height: 30px; | |||
| font-family: Source Sans Pro; | |||
| font-size: 30px; | |||
| line-height: 30px; | |||
| } | |||
| .candidate-lower-header{ | |||
| font-size: 18px; | |||
| line-height: 26px; | |||
| } | |||
| .applicant-cv-button { | |||
| padding: 10px 52px; | |||
| gap: 7px; | |||
| border-radius: 7px; | |||
| width: 180px; | |||
| height: 40px; | |||
| font-size: 10px; | |||
| line-height: 12px; | |||
| text-align: center; | |||
| } | |||
| } | |||
| @media only screen and (max-width:480px) { | |||
| .comment-container { | |||
| width:297px; | |||
| } | |||
| .comment-send-btn{ | |||
| padding: 5px 5px; | |||
| }; | |||
| .comment-container{ | |||
| padding: 20px; | |||
| } | |||
| .candidate-header{ | |||
| height: 20x; | |||
| font-size: 20px; | |||
| line-height: 20px; | |||
| } | |||
| .candidate-lower-header{ | |||
| font-size: 17px; | |||
| line-height:17px; | |||
| } | |||
| } | |||
| @@ -1,9 +1,6 @@ | |||
| .main-candidates-container { | |||
| display: flex; | |||
| flex-direction: column; | |||
| margin-top: 30px; | |||
| margin-left: 100px; | |||
| margin-right: 100px; | |||
| } | |||
| .top-candidates-container { | |||
| @@ -31,7 +31,7 @@ import CloseIcon from "@mui/icons-material/Close"; | |||
| import LogoutIcon from "@mui/icons-material/Logout"; | |||
| import UserProfile from "../Profile/UserProfile"; | |||
| import { useSelector } from "react-redux"; | |||
| import { userSelector } from "../../store/selectors/userSelectors"; | |||
| //import { userSelector } from "../../store/selectors/userSelectors"; | |||
| import { Link } from "react-router-dom"; | |||
| const NavbarComponent = () => { | |||
| @@ -55,7 +55,7 @@ const NavbarComponent = () => { | |||
| let btnRef = useRef(); | |||
| // get authenticated user | |||
| const user = useSelector(userSelector); | |||
| const {user} = useSelector(s => s.user); | |||
| const { t } = useTranslation(); | |||
| @@ -5,20 +5,19 @@ import React from "react"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import avatarLogo from "../../assets/images/Avatar.png"; | |||
| import PropTypes from "prop-types"; | |||
| import { userSelector } from "../../store/selectors/userSelectors"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { logoutUser } from '../../store/actions/login/loginActions' | |||
| import { logoutUser } from "../../store/actions/login/loginActions"; | |||
| const UserProfile = ({ show, innerRef }) => { | |||
| const { t } = useTranslation(); | |||
| const dispatch = useDispatch() | |||
| const dispatch = useDispatch(); | |||
| // const theme = useTheme(); | |||
| // const matches = useMediaQuery(theme.breakpoints.down("sm")); | |||
| const user = useSelector(userSelector); | |||
| const { user } = useSelector((s) => s.user); | |||
| const logout = () => { | |||
| dispatch(logoutUser()) | |||
| } | |||
| dispatch(logoutUser()); | |||
| }; | |||
| return ( | |||
| <Box className={`user-view flex-center ${show && "active"}`}> | |||
| @@ -6,5 +6,6 @@ export const ERROR_PAGE = '/error-page'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const USERS_PAGE = '/users'; | |||
| export const CANDIDATES_PAGE = '/candidates'; | |||
| export const CANDIDATES_DETAILS_PAGE = '/candidates/:id'; | |||
| export const FORGOT_PASSWORD_CONFIRMATION_PAGE = '/forgot-password-confirmation'; | |||
| export const RESET_PASSWORD_PAGE = '/reset-password'; | |||
| @@ -9,6 +9,7 @@ | |||
| @import './assets/styles/components/app-button'; | |||
| @import './assets/styles/components/usersPage'; | |||
| @import './assets/styles/components/candidatesPage'; | |||
| @import './assets/styles/components/candidatePage'; | |||
| @import './assets/styles/components/loader'; | |||
| @import './assets/styles/components/radio'; | |||
| @import './assets/styles/components/modal'; | |||
| @@ -0,0 +1,265 @@ | |||
| import React from "react"; | |||
| import { useEffect, useState, useRef } from "react"; | |||
| import { Link, useParams } from "react-router-dom"; | |||
| import editImage from "../../../src/assets/images/edit.png"; | |||
| import deleteImage from "../../../src/assets/images/delete.png"; | |||
| import planeImage from "../../../src/assets/images/planeVectorBlue.png"; | |||
| import dotnetImage from "../../../src/assets/images/.net_icon.png"; | |||
| import IconButton from "../../components/IconButton/IconButton"; | |||
| import { formatDateTime, formatDate } from "../../util/helpers/dateHelpers"; | |||
| import { setUsersReq } from "../../store/actions/users/usersActions"; | |||
| import { createCandidateComment } from "../../store/actions/candidate/candidateActions"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { MentionsInput, Mention } from "react-mentions"; | |||
| import { fetchCandidate } from "../../store/actions/candidate/candidateActions"; | |||
| import { useMediaQuery } from "@mui/material"; | |||
| import { useTheme } from "@mui/system"; | |||
| const CandidateDetailsPage = () => { | |||
| const dispatch = useDispatch(); | |||
| const { users } = useSelector((s) => s.users); | |||
| const { user } = useSelector((s) => s.user); | |||
| const { candidate } = useSelector((s) => s.candidate); | |||
| const [value, setValue] = useState(""); | |||
| let { id } = useParams(); | |||
| const messageContainer = useRef(); | |||
| const theme = useTheme(); | |||
| const matches = useMediaQuery(theme.breakpoints.down("680")); | |||
| useEffect(() => { | |||
| dispatch(fetchCandidate({ id })); | |||
| dispatch(setUsersReq()); | |||
| }, [dispatch]); | |||
| useEffect(() => { | |||
| messageContainer.current !== undefined | |||
| ? (messageContainer.current.scrollTop = | |||
| messageContainer.current.scrollHeight) | |||
| : ""; | |||
| }, [messageContainer.current, candidate.comments]); | |||
| const handleChange = (event) => { | |||
| setValue(event.target.value); | |||
| }; | |||
| const getArray = () => { | |||
| let newArray = users.map(function (value) { | |||
| return { id: value.id, display: value.firstName + value.lastName }; | |||
| }); | |||
| return newArray; | |||
| }; | |||
| const tranformDisplay = (id, display) => { | |||
| console.log(id); | |||
| return "@" + display + " "; | |||
| }; | |||
| const sendComment = () => { | |||
| // can't send an empty message | |||
| if (value.trim().length === 0) { | |||
| return; | |||
| } | |||
| dispatch( | |||
| createCandidateComment({ | |||
| content: value, | |||
| userId: user.id, | |||
| applicantId: parseInt(id), | |||
| user: { | |||
| id: user.id, | |||
| firstName: user.firstName, | |||
| lastName: user.lastName, | |||
| email: user.email, | |||
| }, | |||
| }) | |||
| ); | |||
| setValue(""); | |||
| }; | |||
| return (candidate && Object.keys(candidate).length === 0) || | |||
| user === undefined ? ( | |||
| <p>Loading...</p> | |||
| ) : ( | |||
| <div className="main-candidate-container pl-144 pt-36px"> | |||
| <div className="l-t-rectangle"></div> | |||
| <div className="r-b-rectangle"></div> | |||
| <div className="top-candidate-container"> | |||
| <div> | |||
| <p className="candidate-header">Kandidat</p> | |||
| <span className="separation-line">|</span> | |||
| <p className="candidate-lower-header"> | |||
| {candidate.firstName} {candidate.lastName} | |||
| </p> | |||
| </div> | |||
| <div className="candidate-option-container"> | |||
| <IconButton className="c-btn c-btn--primary-outlined candidate-btn"> | |||
| Obrisi | |||
| <img src={deleteImage} alt="delete" className="candidates-image" /> | |||
| </IconButton> | |||
| <IconButton className="c-btn c-btn--primary-outlined candidate-btn"> | |||
| Uredi profil | |||
| <img src={editImage} alt="edit" className="candidates-image" /> | |||
| </IconButton> | |||
| </div> | |||
| </div> | |||
| <div className="content-candidate-container"> | |||
| <div className="details-candidate-container"> | |||
| <p style={{ margin: 0 }}> | |||
| {candidate.experience === 0 | |||
| ? "No experience" | |||
| : "Experience:" + candidate.experience} | |||
| </p> | |||
| <div className="technologies-candidate-container"> | |||
| {candidate.technologyApplicants.map((obj, index) => ( | |||
| <div className="technology-candidate-card" key={index}> | |||
| {obj.technology.name} | |||
| </div> | |||
| ))} | |||
| </div> | |||
| <div className="candidate-informations-container"> | |||
| <div className="candidate-informations-sub-container"> | |||
| <div className="candidate-property-container"> | |||
| <p className="informations-candidate-header">Kontakt</p> | |||
| <p className="candidate-property">Email:</p> | |||
| <p className="candidate-property">Telefon:</p> | |||
| </div> | |||
| <div | |||
| style={{ alignSelf: "flex-end", marginLeft: 42 }} | |||
| className="candidate-property-container" | |||
| > | |||
| <p className="candidate-property-value">{candidate.email}</p> | |||
| <p className="candidate-property-value"> | |||
| {candidate.phoneNumber} | |||
| </p> | |||
| </div> | |||
| </div> | |||
| <div className="candidate-informations-sub-container"> | |||
| <div className="candidate-property-container"> | |||
| <p className="informations-candidate-header">Drustvene mreze</p> | |||
| <p className="candidate-property">Linkedln</p> | |||
| <p className="candidate-property">GitHub</p> | |||
| <p className="candidate-property">BitBucket</p> | |||
| </div> | |||
| <div | |||
| style={{ alignSelf: "flex-end", marginLeft: 42 }} | |||
| className="candidate-property-container" | |||
| > | |||
| <p className="candidate-property-value"> | |||
| {candidate.linkedlnLink ?? "/"} | |||
| </p> | |||
| <p className="candidate-property-value"> | |||
| {candidate.gitHubLink ?? "/"} | |||
| </p> | |||
| <p className="candidate-property-value"> | |||
| {candidate.bitBucketLink ?? "/"} | |||
| </p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div className="comment-container"> | |||
| <div | |||
| style={{ | |||
| minHeight: "219px", | |||
| overflowX: "auto", | |||
| paddingBottom: "10px", | |||
| paddingTop: "10px", | |||
| }} | |||
| ref={messageContainer} | |||
| > | |||
| {candidate.comments.map((comment, index) => ( | |||
| <div className="comment-sub-container" key={index}> | |||
| <div className="comment-sender"> | |||
| <p> | |||
| {comment.user.firstName.charAt(0)} | |||
| {comment.user.lastName.charAt(0)} | |||
| </p> | |||
| </div> | |||
| <div className="comment-message"> | |||
| <p className="comment-message-content">{comment.content}</p> | |||
| <p className="comment-message-date"> | |||
| {formatDateTime(comment.dateOfSending)} | |||
| </p> | |||
| </div> | |||
| </div> | |||
| ))} | |||
| </div> | |||
| <div className="comment-separation-line"></div> | |||
| <div className="send-comment-container"> | |||
| <p>Komentar</p> | |||
| <div className="send-comment-sub-container"> | |||
| <MentionsInput | |||
| value={value} | |||
| onChange={handleChange} | |||
| className="comment-input" | |||
| placeholder={"ex. Odlican kandidat"} | |||
| style={{ | |||
| input: !matches | |||
| ? { padding: 18, borderRadius: 7 } | |||
| : { padding: 9, borderRadius: 5 }, | |||
| control: !matches | |||
| ? { | |||
| padding: 18, | |||
| color: "#fff", | |||
| suggestions: { list: { backgroundColor: "#F4F4F4" } }, | |||
| } | |||
| : { | |||
| padding: 9, | |||
| color: "#fff", | |||
| suggestions: { list: { backgroundColor: "#F4F4F4" } }, | |||
| }, | |||
| }} | |||
| > | |||
| <Mention | |||
| trigger="@" | |||
| className="comment-input-list" | |||
| data={getArray} | |||
| displayTransform={(id, display) => | |||
| tranformDisplay(id, display) | |||
| } | |||
| markup="@[__display__]" | |||
| style={{ highlighter: { padding: 18, borderRadius: 7 } }} | |||
| /> | |||
| </MentionsInput> | |||
| <div className="comment-send-btn" onClick={sendComment}> | |||
| <img | |||
| src={planeImage} | |||
| alt="plane" | |||
| className="candidates-image" | |||
| /> | |||
| <p>Komentar</p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div className="applicant-ads-container"> | |||
| <p>Sve prijave</p> | |||
| <div className="applicant-ads-sub-container"> | |||
| {candidate.applicantAds.map((obj, index) => ( | |||
| <div key={index} className="applicant-add"> | |||
| <p className="applicant-add-date"> | |||
| {formatDate(obj.add.createdAt)} | |||
| </p> | |||
| <p className="applicant-add-title">{obj.add.title}</p> | |||
| <img | |||
| src={dotnetImage} | |||
| alt="technology-image" | |||
| className="applicant-add-technology-image" | |||
| /> | |||
| <div className="applicant-add-site">dilig.net</div> | |||
| </div> | |||
| ))} | |||
| </div> | |||
| </div> | |||
| <div className="applicant-ads-buttons-container"> | |||
| <Link to="/candidates" className="applicant-ads-back-button"> | |||
| Nazad na sve kandidate | |||
| </Link> | |||
| <div className="applicant-cv-button">Preuzmi cv</div> | |||
| </div> | |||
| </div> | |||
| ); | |||
| }; | |||
| export default CandidateDetailsPage; | |||
| @@ -2,7 +2,6 @@ import IconButton from "../../components/IconButton/IconButton"; | |||
| import React, { useEffect } from "react"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { fetchCandidates } from "../../store/actions/candidates/candidatesActions"; | |||
| import { refreshUserToken } from "../../store/actions/login/loginActions"; | |||
| import tableImage from "../../assets/images/table.png"; | |||
| import modeImage from "../../assets/images/mode.png"; | |||
| import filterImage from "../../assets/images/filters.png"; | |||
| @@ -10,22 +9,34 @@ import { formatDate } from "../../util/helpers/dateHelpers"; | |||
| import planeImage from "../../assets/images/planeVector.png"; | |||
| import { useMediaQuery } from "@mui/material"; | |||
| import { useTheme } from "@mui/system"; | |||
| import { CANDIDATES_PAGE } from "../../constants/pages"; | |||
| import PropTypes from 'prop-types'; | |||
| const CandidatesPage = () => { | |||
| const CandidatesPage = ({history}) => { | |||
| const dispatch = useDispatch(); | |||
| const {candidates} = useSelector((s) => s.candidates); | |||
| const theme = useTheme(); | |||
| const matches = useMediaQuery(theme.breakpoints.down("sm")); | |||
| useEffect(() => { | |||
| dispatch(refreshUserToken()); | |||
| dispatch(fetchCandidates()); | |||
| }, [dispatch]); | |||
| const navigate = (applicantId) => { | |||
| history.push({ | |||
| pathname: CANDIDATES_PAGE + "/" + applicantId, | |||
| state: { | |||
| from: history.location.pathname, | |||
| }, | |||
| }) | |||
| } | |||
| return candidates[0] === undefined ? ( | |||
| <p>Loading...</p> | |||
| ) : ( | |||
| <div className="main-candidates-container"> | |||
| <div className="main-candidates-container pl-144 pt-36px"> | |||
| <div className="l-t-rectangle"></div> | |||
| <div className="r-b-rectangle"></div> | |||
| <div className="top-candidates-container"> | |||
| {!matches ? ( | |||
| <p className="candidates-header">Kandidati</p> | |||
| @@ -106,7 +117,8 @@ const CandidatesPage = () => { | |||
| <tr | |||
| key={index} | |||
| className="secondaryRow cadidate-row" | |||
| style={{ width: "800px", height: "40px", borderRadius: "12px" }} | |||
| style={{ width: "800px", height: "40px", borderRadius: "12px",cursor:"pointer" }} | |||
| onClick={() => navigate(candidate.applicantId)} | |||
| > | |||
| <td> | |||
| {candidate.firstName} {candidate.lastName} | |||
| @@ -133,4 +145,14 @@ const CandidatesPage = () => { | |||
| ); | |||
| }; | |||
| CandidatesPage.propTypes = { | |||
| history: PropTypes.shape({ | |||
| replace: PropTypes.func, | |||
| push: PropTypes.func, | |||
| location: PropTypes.shape({ | |||
| pathname: PropTypes.string, | |||
| }), | |||
| }), | |||
| } | |||
| export default CandidatesPage; | |||
| @@ -2,17 +2,20 @@ const base = "http://localhost:26081/v1"; | |||
| export default { | |||
| authentications: { | |||
| login: base + "/users/authenticate", | |||
| googleLogin: base + "/users/authenticateGoogle", | |||
| refreshToken: base + "/users/refresh", | |||
| logout: base + "/users/logout?userId={userId}", | |||
| forgetPassword: base + "/users/ForgotPassword", | |||
| resetPassword: base + "/users/RessetPassword", | |||
| login: base + "/authentications/authenticate", | |||
| googleLogin: base + "/authentications/authenticateGoogle", | |||
| refreshToken: base + "/authentications/refresh", | |||
| logout: base + "/authentications/logout?userId={userId}", | |||
| forgetPassword: base + "/authentications/ForgotPassword", | |||
| resetPassword: base + "/authentications/RessetPassword", | |||
| }, | |||
| users:{ | |||
| allUsers:'http://localhost:26081/v1/users', | |||
| }, | |||
| candidates:{ | |||
| allCandidates:base + "/applicants" | |||
| allCandidates:base + "/applicants", | |||
| }, | |||
| comments:{ | |||
| addComment:base + '/comments' | |||
| } | |||
| }; | |||
| @@ -1,4 +1,6 @@ | |||
| import { getRequest } from "."; | |||
| import { getRequest, postRequest } from "."; | |||
| import apiEndpoints from "./apiEndpoints"; | |||
| export const getAllCandidates = () => getRequest(apiEndpoints.candidates.allCandidates) | |||
| export const getAllCandidates = () => getRequest(apiEndpoints.candidates.allCandidates) | |||
| export const getCandidate = (id) => getRequest(apiEndpoints.candidates.allCandidates + "/" + id) | |||
| export const createComment = (data) => postRequest(apiEndpoints.comments.addComment,data) | |||
| @@ -0,0 +1,20 @@ | |||
| import { | |||
| createErrorType, | |||
| createFetchType, | |||
| createLoadingType, | |||
| createSuccessType, | |||
| } from "../actionHelpers"; | |||
| const CANDIDATE_SCOPE = 'CANDIDATE' | |||
| const CANDIDATE_SCOPE_COMMENTS = 'CANDIDATE_COMMENTS' | |||
| export const CANDIDATE_FETCH = createFetchType(CANDIDATE_SCOPE); | |||
| export const CANDIDATE_ERROR = createErrorType(CANDIDATE_SCOPE) | |||
| export const CANDIDATE_SUCCESS = createSuccessType(CANDIDATE_SCOPE) | |||
| export const CANDIDATE_LOADING = createLoadingType(CANDIDATE_SCOPE) | |||
| export const CANDIDATE_COMMENTS_FETCH = createFetchType(CANDIDATE_SCOPE_COMMENTS); | |||
| export const CANDIDATE_COMMENTS_ERROR = createErrorType(CANDIDATE_SCOPE_COMMENTS) | |||
| export const CANDIDATE_COMMENTS_SUCCESS = createSuccessType(CANDIDATE_SCOPE_COMMENTS) | |||
| export const CANDIDATE_COMMENTS_LOADING = createLoadingType(CANDIDATE_SCOPE_COMMENTS) | |||
| @@ -0,0 +1,38 @@ | |||
| import { | |||
| CANDIDATE_FETCH, | |||
| CANDIDATE_ERROR, | |||
| CANDIDATE_SUCCESS, | |||
| CANDIDATE_COMMENTS_FETCH, | |||
| CANDIDATE_COMMENTS_ERROR, | |||
| CANDIDATE_COMMENTS_SUCCESS, | |||
| } from "./candidateActionConstants"; | |||
| export const fetchCandidate = (payload) => ({ | |||
| type: CANDIDATE_FETCH, | |||
| payload, | |||
| }); | |||
| export const fetchCandidateError = (payload) => ({ | |||
| type: CANDIDATE_ERROR, | |||
| payload, | |||
| }); | |||
| export const fetchCandidateSuccess = (payload) => ({ | |||
| type: CANDIDATE_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const createCandidateComment = (payload) => ({ | |||
| type: CANDIDATE_COMMENTS_FETCH, | |||
| payload, | |||
| }); | |||
| export const createCandidateCommentError = (payload) => ({ | |||
| type: CANDIDATE_COMMENTS_ERROR, | |||
| payload, | |||
| }); | |||
| export const createCandidateCommentSuccess = (payload) => ({ | |||
| type: CANDIDATE_COMMENTS_SUCCESS, | |||
| payload, | |||
| }); | |||
| @@ -16,4 +16,5 @@ import { | |||
| export const fetchCandidatesSuccess = (payload) => ({ | |||
| type: CANDIDATES_SUCCESS, | |||
| payload, | |||
| }); | |||
| }); | |||
| @@ -10,7 +10,7 @@ export default ({ dispatch }) => (next) => (action) => { | |||
| if ( | |||
| error.response.config.url !== apiEndpoints.authentications.login && | |||
| error.response.config.url !== | |||
| apiEndpoints.authentications.confirmSecurityQuestion && | |||
| apiEndpoints.authentications.confirmSecurityQuestion && | |||
| error.response.status === 401 | |||
| ) { | |||
| return dispatch(logoutUser()); | |||
| @@ -0,0 +1,75 @@ | |||
| import createReducer from "../../utils/createReducer"; | |||
| import { | |||
| CANDIDATE_ERROR, | |||
| CANDIDATE_SUCCESS, | |||
| CANDIDATE_COMMENTS_SUCCESS, | |||
| CANDIDATE_COMMENTS_ERROR, | |||
| } from "../../actions/candidate/candidateActionConstants"; | |||
| const initialState = { | |||
| candidate: {}, | |||
| errorMessage: "", | |||
| }; | |||
| export default createReducer( | |||
| { | |||
| [CANDIDATE_SUCCESS]: setCandidate, | |||
| [CANDIDATE_ERROR]: setError, | |||
| [CANDIDATE_COMMENTS_SUCCESS]: setComments, | |||
| [CANDIDATE_COMMENTS_ERROR]: setCommentsError, | |||
| }, | |||
| initialState | |||
| ); | |||
| function setCandidate(state, action) { | |||
| return { | |||
| ...state, | |||
| candidate: action.payload, | |||
| }; | |||
| } | |||
| function setError(state, action) { | |||
| return { | |||
| ...state, | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| function setComments(state, action) { | |||
| const currentDate = new Date(); | |||
| var datetime = | |||
| currentDate.getFullYear() + | |||
| "-" + | |||
| (currentDate.getMonth() + 1) + | |||
| "-" + | |||
| currentDate.getDate() + | |||
| "T" + | |||
| currentDate.getHours() + | |||
| ":" + | |||
| (currentDate.getMinutes() <= 9 | |||
| ? "0" + currentDate.getMinutes() | |||
| : currentDate.getMinutes()) + | |||
| ":" + | |||
| (currentDate.getSeconds() <= 9 | |||
| ? "0" + currentDate.getSeconds() | |||
| : currentDate.getSeconds()); | |||
| const obj = { | |||
| content: action.payload.myObj.content, | |||
| dateOfSending: datetime, | |||
| user: action.payload.user, | |||
| }; | |||
| return { | |||
| ...state, | |||
| candidate: { | |||
| ...state.candidate, | |||
| comments: [...state.candidate.comments, obj], | |||
| }, | |||
| }; | |||
| } | |||
| function setCommentsError(state, action) { | |||
| return { | |||
| ...state, | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| @@ -12,7 +12,7 @@ const initialState = { | |||
| export default createReducer( | |||
| { | |||
| [CANDIDATES_SUCCESS]: setCandidates, | |||
| [CANDIDATES_ERROR]: setError, | |||
| [CANDIDATES_ERROR]: setError | |||
| }, | |||
| initialState | |||
| ); | |||
| @@ -29,4 +29,4 @@ function setError(state, action) { | |||
| ...state, | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| } | |||
| @@ -5,6 +5,7 @@ import userReducer from './user/userReducer'; | |||
| import randomDataReducer from './randomData/randomDataReducer'; | |||
| import usersReducer from './user/usersReducer'; | |||
| import candidatesReducer from './candidates/candidatesReducer'; | |||
| import candidateReducer from './candidate/candidateReducer'; | |||
| export default combineReducers({ | |||
| login: loginReducer, | |||
| @@ -12,5 +13,6 @@ export default combineReducers({ | |||
| loading:loadingReducer, | |||
| randomData: randomDataReducer, | |||
| users: usersReducer, | |||
| candidates:candidatesReducer | |||
| candidates:candidatesReducer, | |||
| candidate:candidateReducer | |||
| }); | |||
| @@ -1,36 +1,35 @@ | |||
| import createReducer from '../../utils/createReducer'; | |||
| import createReducer from "../../utils/createReducer"; | |||
| import { | |||
| SET_USER, | |||
| SET_USER_ERROR, | |||
| RESET_USER_STATE | |||
| } from '../../actions/user/userActionConstants'; | |||
| RESET_USER_STATE, | |||
| } from "../../actions/user/userActionConstants"; | |||
| const initialState = { | |||
| id:"", | |||
| firstName:"", | |||
| lastName:"", | |||
| username:"", | |||
| token:"", | |||
| refreshToken:"" | |||
| user: { | |||
| id: "", | |||
| firstName: "", | |||
| lastName: "", | |||
| username: "", | |||
| token: "", | |||
| refreshToken: "", | |||
| }, | |||
| errorMessage: "", | |||
| }; | |||
| export default createReducer( | |||
| { | |||
| [SET_USER]: setUser, | |||
| [SET_USER_ERROR]: setUserError, | |||
| [RESET_USER_STATE]:resetUserState | |||
| [RESET_USER_STATE]: resetUserState, | |||
| }, | |||
| initialState, | |||
| initialState | |||
| ); | |||
| function setUser(state, action) { | |||
| return { | |||
| id:action.payload.id, | |||
| firstName:action.payload.firstName, | |||
| lastName:action.payload.lastName, | |||
| username:action.payload.username, | |||
| token:action.payload.token, | |||
| refreshToken:action.payload.refreshToken, | |||
| ...state, | |||
| user: action.payload, | |||
| }; | |||
| } | |||
| @@ -19,7 +19,6 @@ export default createReducer( | |||
| ); | |||
| function setStateUsers(state, action) { | |||
| console.log("POZIV"); | |||
| return { | |||
| ...state, | |||
| users: action.payload, | |||
| @@ -1,15 +1,16 @@ | |||
| import { all, call, put, takeEvery } from "redux-saga/effects"; | |||
| import { JWT_TOKEN } from "../../constants/localStorage"; | |||
| import { addHeaderToken } from "../../request"; | |||
| import { getAllCandidates } from "../../request/candidatesRequest"; | |||
| import { getAllCandidates,createComment,getCandidate } from "../../request/candidatesRequest"; | |||
| import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers"; | |||
| import { CANDIDATES_FETCH } from "../actions/candidates/candidatesActionConstants"; | |||
| import { CANDIDATES_FETCH} from "../actions/candidates/candidatesActionConstants"; | |||
| import { fetchCandidatesError,fetchCandidatesSuccess } from "../actions/candidates/candidatesActions"; | |||
| import { rejectErrorCodeHelper } from '../../util/helpers/rejectErrorCodeHelper'; | |||
| import { fetchCandidateError, fetchCandidateSuccess,createCandidateCommentSuccess,createCandidateCommentError } from "../actions/candidate/candidateActions"; | |||
| import { CANDIDATE_FETCH,CANDIDATE_COMMENTS_FETCH } from "../actions/candidate/candidateActionConstants"; | |||
| export function* getCandidates() { | |||
| try { | |||
| console.log('oVde smo') | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| const {data} = yield call(getAllCandidates); | |||
| @@ -20,6 +21,33 @@ export function* getCandidates() { | |||
| } | |||
| } | |||
| export function* getSingleCandidate({payload}){ | |||
| try{ | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| const {data} = yield call(getCandidate,payload.id) | |||
| yield put(fetchCandidateSuccess(data)) | |||
| } catch(error){ | |||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||
| yield put(fetchCandidateError(errorMessage)) | |||
| } | |||
| } | |||
| export function* addComment(data) { | |||
| const {user,...myObj} = data.payload | |||
| try{ | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| yield call(createComment,myObj); | |||
| yield put(createCandidateCommentSuccess({user,myObj})) | |||
| } catch (error){ | |||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||
| yield put(createCandidateCommentError(errorMessage)) | |||
| } | |||
| } | |||
| export default function* candidatesSaga() { | |||
| yield all([takeEvery(CANDIDATES_FETCH, getCandidates)]); | |||
| yield all([takeEvery(CANDIDATE_FETCH, getSingleCandidate)]); | |||
| yield all([takeEvery(CANDIDATE_COMMENTS_FETCH, addComment)]); | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| import { createSelector } from "@reduxjs/toolkit"; | |||
| export const candidateSelector = (state) => state.candidate; | |||
| export const selectCandidate = createSelector( | |||
| candidateSelector, | |||
| (state) => state.candidate, | |||
| ); | |||
| @@ -9,7 +9,7 @@ export function formatDate(date, fmt = 'dd.MM.y', locale = enUS) { | |||
| export function formatDateTime(date) { | |||
| const dt = new Date(date); | |||
| return format(dt, 'MM/dd/y hh:mm aa'); | |||
| return format(dt, 'hh:mm dd.MM.y'); | |||
| } | |||
| export function getDateDay(date) { | |||
| @@ -1156,7 +1156,7 @@ | |||
| "core-js-pure" "^3.0.0" | |||
| "regenerator-runtime" "^0.13.4" | |||
| "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@7.12.1": | |||
| "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@7.12.1": | |||
| "integrity" "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==" | |||
| "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz" | |||
| "version" "7.12.1" | |||
| @@ -1205,6 +1205,13 @@ | |||
| dependencies: | |||
| "regenerator-runtime" "^0.13.4" | |||
| "@babel/runtime@7.4.5": | |||
| "integrity" "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==" | |||
| "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz" | |||
| "version" "7.4.5" | |||
| dependencies: | |||
| "regenerator-runtime" "^0.13.2" | |||
| "@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.3.3": | |||
| "integrity" "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==" | |||
| "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz" | |||
| @@ -10338,7 +10345,7 @@ | |||
| "strip-ansi" "6.0.0" | |||
| "text-table" "0.2.0" | |||
| "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@^17.0.2 || ^18.0.0", "react-dom@<18.0.0", "react-dom@>=16.6.0": | |||
| "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@^17.0.2 || ^18.0.0", "react-dom@<18.0.0", "react-dom@>=16.6.0", "react-dom@>=16.8.3": | |||
| "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" | |||
| "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" | |||
| "version" "17.0.2" | |||
| @@ -10413,6 +10420,16 @@ | |||
| "resolved" "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" | |||
| "version" "18.2.0" | |||
| "react-mentions@^4.4.7": | |||
| "integrity" "sha512-VNriu2h/uOB+RS0mwZgPG2Vf+UtdDvRh5zbXa2TNc1WqacKuNDgTdhlbo9LEOZRBxRzIeTUYQmYJ7p9M9rDHqQ==" | |||
| "resolved" "https://registry.npmjs.org/react-mentions/-/react-mentions-4.4.7.tgz" | |||
| "version" "4.4.7" | |||
| dependencies: | |||
| "@babel/runtime" "7.4.5" | |||
| "invariant" "^2.2.4" | |||
| "prop-types" "^15.5.8" | |||
| "substyle" "^9.1.0" | |||
| "react-redux@^7.2.1 || ^8.0.2", "react-redux@^7.2.4": | |||
| "integrity" "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==" | |||
| "resolved" "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz" | |||
| @@ -10564,7 +10581,7 @@ | |||
| "loose-envify" "^1.4.0" | |||
| "prop-types" "^15.6.2" | |||
| "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.3.0 || ^17.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.3 || ^17 || ^18", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", "react@^17.0.2", "react@^17.0.2 || ^18.0.0", "react@^18.2.0", "react@<18.0.0", "react@>= 16", "react@>= 16.8.0", "react@>=15", "react@>=16.6.0", "react@>=16.8.0", "react@17.0.2": | |||
| "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.3.0 || ^17.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.3 || ^17 || ^18", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", "react@^17.0.2", "react@^17.0.2 || ^18.0.0", "react@^18.2.0", "react@<18.0.0", "react@>= 16", "react@>= 16.8.0", "react@>=15", "react@>=16.6.0", "react@>=16.8.0", "react@>=16.8.3", "react@17.0.2": | |||
| "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" | |||
| "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" | |||
| "version" "17.0.2" | |||
| @@ -10801,7 +10818,7 @@ | |||
| "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz" | |||
| "version" "0.11.1" | |||
| "regenerator-runtime@^0.13.4", "regenerator-runtime@^0.13.7": | |||
| "regenerator-runtime@^0.13.2", "regenerator-runtime@^0.13.4", "regenerator-runtime@^0.13.7": | |||
| "integrity" "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" | |||
| "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz" | |||
| "version" "0.13.7" | |||
| @@ -12042,6 +12059,14 @@ | |||
| "resolved" "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" | |||
| "version" "4.0.13" | |||
| "substyle@^9.1.0": | |||
| "integrity" "sha512-VOngeq/W1/UkxiGzeqVvDbGDPM8XgUyJVWjrqeh+GgKqspEPiLYndK+XRcsKUHM5Muz/++1ctJ1QCF/OqRiKWA==" | |||
| "resolved" "https://registry.npmjs.org/substyle/-/substyle-9.4.1.tgz" | |||
| "version" "9.4.1" | |||
| dependencies: | |||
| "@babel/runtime" "^7.3.4" | |||
| "invariant" "^2.2.4" | |||
| "supports-color@^5.3.0": | |||
| "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" | |||
| "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" | |||