├── .gitignore
├── Diagram.png
├── README.md
├── package-lock.json
├── package.json
├── public
├── index.html
└── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── layouts
├── Dashboard.jsx
├── Footer.jsx
├── Navi.jsx
├── SignedIn.jsx
└── SignedOut.jsx
├── logo.svg
├── pages
├── ChoosingSignInMethod.jsx
├── ChoosingSignUpMethod.jsx
├── Employers
│ ├── EmployerDetailPage.jsx
│ ├── EmployerList.jsx
│ ├── EmployerSignUpPage.jsx
│ └── JobAddPage.jsx
├── JobPositionList.jsx
├── JobSeekers
│ ├── JobSeekerDetail.jsx
│ ├── JobSeekerList.jsx
│ └── JobSeekerSignUpPage.jsx
├── Jobs
│ ├── JobDetailPage.jsx
│ └── JobList.jsx
├── MainPage.jsx
├── SignInPage.jsx
└── SystemUsers
│ ├── JobConfirmationPanel.jsx
│ └── SystemUserSignUpPage.jsx
├── reportWebVitals.js
├── services
├── ActivationPanelService.js
├── CityService.js
├── EmployerService.js
├── JobPositionService.js
├── JobSeekerService.js
├── JobService.js
├── WorkPlaceService.js
└── WorkTimeService.js
├── setupTests.js
└── store
├── configureStore.js
└── rootReducer.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 | node_modules
25 |
--------------------------------------------------------------------------------
/Diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrPand-21/HRMS_Frontend/1732033d87311d30ef0ee3f81a3390a53d2688e7/Diagram.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
24 |
25 | # About the Project
26 |
27 | []()
28 | [](https://nodejs.org/)
29 | [](https://tr.reactjs.org/)
30 | [](https://getbootstrap.com/)
31 | [](https://sass-lang.com/)
32 | [](https://github.com/facebook/create-react-app)
33 | [](http://forthebadge.com)
34 |
35 | HRMS Frontend project. (You can access the backend [here](https://github.com/MrPand-21/HRMS_Backend) and use them together to work with real database and backend)
36 |
37 | ### UML Component Diagram
38 |
39 | 
40 |
41 | ## Installation
42 |
43 | To get this project you can run the following comments in your terminal which is opened in the folder where you want to copy to.
44 |
45 | ```bash
46 | # clones the selected repository
47 | $ git clone https://github.com/MrPand-21/HRMS_Frontend
48 | ```
49 |
50 | After opened the project in the terminal, you can write
51 |
52 | ``` bash
53 | # installs the dependencies
54 | $ npm i
55 | ```
56 |
57 | ## Usage
58 |
59 | In the project directory, you can run:
60 |
61 | ```bash
62 | # runs the app in the development mode.
63 | $ npm start
64 | ```
65 |
66 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
67 |
68 | The page will reload if you make edits.\
69 | You will also see any lint errors in the console.
70 |
71 | ```bash
72 | # lunches the test runner in the interactive watch mode.
73 | $ npm test
74 | ```
75 |
76 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
77 |
78 | ```bash
79 | # builds the app for production to the `build` folder.
80 | $ npm run build
81 | ```
82 |
83 | It correctly bundles React in production mode and optimizes the build for the best performance.
84 |
85 | The build is minified and the filenames include the hashes.\
86 | Your app is ready to be deployed!
87 |
88 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
89 |
90 | ```bash
91 | #you may want to omit "eject"
92 | $ npm run eject
93 | ```
94 |
95 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
96 |
97 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
98 |
99 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
100 |
101 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
102 |
103 | ## Contributing
104 |
105 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. Right now there is only one branch which is master.
106 |
107 | 1. Fork the Project
108 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
109 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
110 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
111 | 5. Open a Pull Request
112 |
113 | ## Learn More
114 |
115 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
116 |
117 | To learn React, check out the [React documentation](https://reactjs.org/).
118 |
119 | * [Code Splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
120 | * [Analyzing the Bundle Size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
121 | * [Making a Progressive Web App](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
122 | * [Advanced Configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
123 | * [Deployment](https://facebook.github.io/create-react-app/docs/deployment)
124 | * [npm run build fails to minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
125 |
126 | ## Credits
127 |
128 | [Carabelli](MrPanda+HRMS_Frontend@protonmail.ch)
129 |
130 | #### Acknowledgements
131 |
132 | - [Engin Demirog](https://www.linkedin.com/in/engindemirog)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hrms-project",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.14.1",
7 | "@testing-library/react": "^11.2.7",
8 | "@testing-library/user-event": "^12.8.3",
9 | "axios": "^0.21.1",
10 | "formik": "^2.2.9",
11 | "react": "^17.0.2",
12 | "react-dom": "^17.0.2",
13 | "react-router-dom": "^5.2.0",
14 | "react-scripts": "4.0.3",
15 | "react-toastify": "^7.0.4",
16 | "semantic-ui-css": "^2.4.1",
17 | "semantic-ui-react": "^2.0.3",
18 | "web-vitals": "^1.1.2",
19 | "yup": "^0.32.9"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "react-scripts build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | HRMS Project
12 |
13 |
14 | You need to enable JavaScript to run this app.
15 |
16 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "HRMS Project",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | #jobSeekerDetail{
6 | background-color: #f09595c0;
7 | }
8 |
9 | #menu-blank{
10 | padding-bottom: 500px;
11 | }
12 | .blue{
13 | background: blue;
14 | }
15 | .marginLeft{
16 | margin-left: 2.7em;
17 | }
18 |
19 | .labelForJobAddFields{
20 | margin-right: 2em;
21 | }
22 |
23 | .paddingRightSmall{
24 | padding-right:1em;
25 | }
26 |
27 | .paddingRight{
28 | padding-right:2em;
29 | }
30 |
31 | .paddingRightMedium{
32 | padding-right:3em;
33 | }
34 |
35 | .paddingRightLarge{
36 | padding-right:5em;
37 | }
38 |
39 | #headerForJob{
40 | margin-bottom: 2em;
41 | }
42 |
43 | #deadlineField{
44 | margin-right: -54px;
45 | }
46 |
47 | .clearMargins{
48 | margin-top: 0px;
49 | margin-bottom: 0px;
50 | }
51 |
52 | .marginBottom{
53 | margin-bottom: 1em;
54 |
55 | }
56 | .marginTopSmall{
57 | margin-top: 1em;
58 |
59 | }
60 |
61 | .marginBottomMedium{
62 | margin-bottom: 2em;
63 | }
64 | .marginTop{
65 | margin-top: 5em;
66 | }
67 | #bg-for-menu{
68 |
69 | position: absolute;
70 | z-index: 0;
71 | height: 100%;
72 | width:100px;
73 | box-sizing: border-box;
74 | background: linear-gradient(180deg,#8686d5,#00d4ff);
75 | clip-path: polygon(0 0, 56% 0, 100% 0%, 0% 100%);
76 |
77 | }
78 |
79 | div [class*="left floated"] {
80 | float: left;
81 | margin-left: 0.25em;
82 | }
83 |
84 | div [class*="right floated"] {
85 | float: right;
86 | margin-right: 0.25em;
87 | }
88 |
89 | .labelForEmployerSignUp{
90 | margin-right: 10px;
91 | font-size:22px;
92 | color: rgb(13, 158, 255);
93 | text-align: center;
94 | }
95 |
96 | .labelForSystemUserSignUp{
97 | margin-right: 10px;
98 | font-size:22px;
99 | color: rgb(13, 158, 255);
100 | text-align: center;
101 | }
102 |
103 | .employer-header{
104 | margin-top: 3em !important;
105 | text-align: center;
106 | }
107 |
108 | .jobSeeker-header{
109 | margin-top: 3em !important;
110 | text-align: center;
111 | }
112 |
113 | #menu{
114 |
115 | background-color: #1B1C1D;
116 | display: flex;
117 | justify-content: center;
118 | align-items: top;
119 | min-height: 100vh;
120 | height:110%;
121 |
122 | }
123 |
124 | #footer{
125 | background-color: #1B1C1D;
126 | }
127 |
128 | #content-area{
129 | margin-top: 3em;
130 | margin-right: 4em;
131 | }
132 |
133 | #white-jobseeker{
134 | color:white;
135 | }
136 |
137 | #white-employername{
138 | color:white;
139 | }
140 |
141 | * {
142 | box-sizing: border-box;
143 | margin: 0;
144 | padding: 0;
145 | text-rendering: optimizeLegibility;
146 | -webkit-font-smoothing: antialiased;
147 | -moz-osx-font-smoothing: grayscale;
148 | -webkit-tap-highlight-color: transparent;
149 | }
150 |
151 | html {
152 | font-size: 16px;
153 | margin: 0;
154 | padding: 0;
155 | text-decoration-skip-ink: "auto";
156 | }
157 |
158 | :root {
159 | --gray-900: #1a202c;
160 | --gray-800: #2d3748;
161 | --gray-700: #4a5568;
162 | --gray-600: #718096;
163 | --gray-500: #a0aec0;
164 | --gray-400: #cbd5e0;
165 | --gray-300: #e2e8f0;
166 | --gray-200: #edf2f7;
167 | --gray-100: #f7fafc;
168 | --red-100: #fff5f5;
169 | --red-200: #fed7d7;
170 | --red-300: #feb2b2;
171 | --red-400: #fc8181;
172 | --red-500: #f56565;
173 | --red-600: #e53e3e;
174 | --red-700: #c53030;
175 | --red-800: #9b2c2c;
176 | --red-900: #742a2a;
177 | --blue-100: #ebf8ff;
178 | --blue-200: #bee3f8;
179 | --blue-300: #90cdf4;
180 | --blue-400: #63b3ed;
181 | --blue-500: #4299e1;
182 | --blue-600: #3182ce;
183 | --blue-700: #2b6cb0;
184 | --blue-800: #2c5282;
185 | --blue-900: #2a4365;
186 | --white: white;
187 | --red: #f56565;
188 | --text-decoration-color: var(--gray-400);
189 | --text-color: var(--gray-800);
190 | --focus-ring-color: var(--blue-500);
191 | }
192 |
193 | body {
194 | padding: 0;
195 | margin: calc((100vh / 25) * 1.563) calc((100vw / 25) * 1.563);
196 | background-color: white;
197 | font-weight: 400;
198 | line-height: 1.563;
199 | color: var(--text-color);
200 | caret-color: var(--text-color);
201 | }
202 |
203 | @media (prefers-color-scheme: dark) {
204 | body {
205 | color: white;
206 | background-color: var(--gray-900);
207 | caret-color: white;
208 | }
209 | }
210 |
211 | /* Typography
212 | ––––––––––––––––––––––––––––––––– */
213 |
214 | h1,
215 | h2,
216 | h3,
217 | h4,
218 | h5,
219 | h6 {
220 | margin-bottom: 1rem;
221 | margin-top: 1em;
222 | font-weight: bold;
223 | }
224 |
225 | h1 {
226 | font-size: 3.052rem !important;
227 | line-height: 1;
228 | }
229 |
230 | h2 {
231 | font-size: 2.441rem;
232 | line-height: 1.2;
233 | }
234 |
235 | h3 {
236 | font-size: 1.953rem;
237 | line-height: 1.2;
238 | }
239 |
240 | h4 {
241 | font-size: 1.563rem;
242 | line-height: 1.3;
243 | }
244 |
245 | h5 {
246 | font-size: 1.25rem;
247 | line-height: 1.4;
248 | }
249 |
250 | h6 {
251 | font-size: 1rem;
252 |
253 | line-height: 1.5;
254 | }
255 |
256 | p {
257 | margin-bottom: 1.563rem;
258 | }
259 |
260 | p > *:last-child {
261 | margin-bottom: 0;
262 | }
263 |
264 | a {
265 | color: inherit;
266 | text-decoration: underline;
267 | text-decoration-color: var(--text-decoration-color);
268 | -webkit-text-decoration-color: var(--text-decoration-color);
269 | border-radius: 5px;
270 | text-underline-offset: 2px;
271 | text-decoration-thickness: 2px;
272 | }
273 |
274 | @media (hover: hover) {
275 | a:hover {
276 | text-decoration-color: var(--gray-800);
277 | }
278 | }
279 |
280 | @media (hover: hover) and (prefers-color-scheme: dark) {
281 | a:hover {
282 | text-decoration-color: white;
283 | }
284 | }
285 |
286 | @media (prefers-color-scheme: dark) {
287 | a {
288 | text-decoration-color: var(--gray-700);
289 | -webkit-text-decoration-color: var(--gray-700);
290 | }
291 | }
292 |
293 | a:focus-visible {
294 | box-shadow: 0 0 0 2px var(--focus-ring-color);
295 | outline: none;
296 | }
297 |
298 | small {
299 | font-size: 0.888rem;
300 | }
301 |
302 | hr {
303 | border: 1px solid var(--gray-700);
304 | margin: 3.052rem 0;
305 | }
306 |
307 | /* Form
308 | ––––––––––––––––––––––––––––––––– */
309 | label {
310 | font-weight: bold;
311 | display: flex;
312 | }
313 |
314 | input[type="email"],
315 | input[type="text"],
316 | input[type="number"] {
317 | padding: 0.65rem 0.5rem;
318 | border: 2px solid var(--gray-200);
319 | background-color: var(--gray-100);
320 | color: var(--gray-800);
321 | border-radius: 10px;
322 | -webkit-appearance: none;
323 | -moz-appearance: none;
324 | appearance: none;
325 | }
326 |
327 | @media (prefers-color-scheme: dark) {
328 | input[type="email"],
329 | input[type="text"],
330 | input[type="number"] {
331 | background-color: var(--gray-800);
332 | border-color: var(--gray-700);
333 | color: white;
334 | }
335 |
336 | input[type="email"]::placeholder,
337 | input[type="text"]::placeholder,
338 | input[type="number"]::placeholder,
339 | select,
340 | textarea {
341 | color: var(--gray-500);
342 | }
343 | }
344 |
345 | input[type="email"],
346 | input[type="text"],
347 | input[type="number"],
348 | textarea,
349 | select {
350 | width: 400px;
351 | }
352 |
353 | select {
354 | margin: 0;
355 | -webkit-appearance: none;
356 | box-sizing: border-box;
357 | padding: 0.65rem 0.5rem;
358 | font-size: 1rem;
359 | border: 2px solid var(--gray-200);
360 | border-radius: 10px;
361 | color: var(--gray-700);
362 | height: auto;
363 | background-color: var(--gray-100);
364 | background-image: url('data:image/svg+xml;utf8, ');
365 | background-repeat: no-repeat;
366 | background-size: 1rem;
367 | background-position: center right 0.5rem;
368 | }
369 |
370 | @media (prefers-color-scheme: dark) {
371 | select {
372 | background-color: var(--gray-800);
373 | background-image: url('data:image/svg+xml;utf8, ');
374 | border-color: var(--gray-700);
375 | color: white;
376 | }
377 | }
378 |
379 | textarea {
380 | -webkit-appearance: none;
381 | -moz-appearance: none;
382 | appearance: none;
383 | border: 2px solid var(--gray-200);
384 | color: var(--gray-700);
385 | border-radius: 10px;
386 | resize: vertical;
387 | background-color: var(--gray-100);
388 | box-sizing: border-box;
389 | padding: 0.65rem 0.5rem;
390 | }
391 |
392 | @media (prefers-color-scheme: dark) {
393 | textarea {
394 | background-color: var(--gray-800);
395 | border-color: var(--gray-700);
396 | color: white;
397 | }
398 | }
399 |
400 | input:focus,
401 | select:focus,
402 | textarea:focus {
403 | outline: none;
404 | border: 2px solid var(--focus-ring-color);
405 | }
406 |
407 | input:invalid,
408 | select:invalid,
409 | textarea:invalid {
410 | border: 2px solid #ff7d87;
411 | box-shadow: none;
412 | }
413 |
414 | input[type="checkbox"] {
415 | display: inline-block;
416 | height: 1rem;
417 | border-radius: 5px;
418 | -webkit-appearance: none;
419 | -moz-appearance: none;
420 | appearance: none;
421 | border: 2px solid var(--gray-300);
422 | width: 1rem;
423 | background-color: white;
424 | align-self: center;
425 | margin-right: 0.5rem;
426 | }
427 |
428 | @media (prefers-color-scheme: dark) {
429 | input[type="checkbox"] {
430 | background-color: var(--gray-800);
431 | border-color: var(--gray-600);
432 | }
433 | }
434 |
435 | input[type="checkbox"]:hover {
436 | cursor: pointer;
437 | }
438 |
439 | input[type="checkbox"]:checked {
440 | background-image: url('data:image/svg+xml;utf8, ');
441 | background-size: contain;
442 | background-color: var(--gray-700);
443 | border: 2px solid var(--gray-700);
444 | }
445 |
446 | input[type="checkbox"]:focus-visible,
447 | input[type="checkbox"]:checked:focus-visible {
448 | border-color: var(--focus-ring-color);
449 | }
450 |
451 | @media (prefers-color-scheme: dark) {
452 | input[type="checkbox"]:checked {
453 | background-image: url('data:image/svg+xml;utf8, ');
454 | background-color: white;
455 | border: 2px solid white;
456 | }
457 | }
458 |
459 | input[type="radio"] {
460 | -webkit-appearance: none;
461 | -moz-appearance: none;
462 | appearance: none;
463 | border-radius: 50%;
464 | border: 2px solid var(--gray-300);
465 | height: 1rem;
466 | width: 1rem;
467 | margin-right: 0.5rem;
468 | align-self: center;
469 | justify-content: center;
470 | position: relative;
471 | display: flex;
472 | }
473 |
474 | @media (prefers-color-scheme: dark) {
475 | input[type="radio"] {
476 | border: 2px solid white;
477 | }
478 | }
479 |
480 | @media (hover: hover) {
481 | input[type="radio"]:hover {
482 | cursor: pointer;
483 | }
484 | }
485 |
486 | input[type="radio"]:checked {
487 | border: 2px solid var(--gray-700);
488 | }
489 |
490 | input[type="radio"]:focus-visible,
491 | input[type="radio"]:checked:focus-visible {
492 | border-color: var(--focus-ring-color);
493 | }
494 |
495 | @media (prefers-color-scheme: dark) {
496 | input[type="radio"]:checked {
497 | border: 2px solid white;
498 | }
499 | }
500 |
501 | input[type="radio"]:checked::before {
502 | content: "";
503 | width: calc(100% - 4px);
504 | height: calc(100% - 4px);
505 | background-color: var(--gray-700);
506 | align-self: center;
507 | border-radius: 50%;
508 | }
509 |
510 | @media (prefers-color-scheme: dark) {
511 | input[type="radio"]:checked::before {
512 | background-color: white;
513 | }
514 | }
515 |
516 | input[type="submit"],
517 | input[type="reset"],
518 | input[type="button"],
519 | button {
520 | padding: 0.5rem 1.25rem;
521 | border-radius: 10px;
522 | background-color: var(--gray-700);
523 | border: 2px solid var(--gray-700);
524 | color: white;
525 | text-decoration: none;
526 | font-weight: bold;
527 | margin-bottom: 1rem;
528 | -webkit-appearance: none;
529 | -moz-appearance: none;
530 | appearance: none;
531 | display: inline-block;
532 | transition: background-color 200ms ease-in-out, border 200ms ease-in-out,
533 | transform 200ms ease-in-out;
534 | -webkit-touch-callout: none;
535 | -webkit-user-select: none;
536 | user-select: none;
537 | }
538 |
539 | @media (prefers-color-scheme: dark) {
540 | input[type="submit"],
541 | input[type="reset"],
542 | input[type="button"],
543 | button {
544 | background-color: white;
545 | border: 2px solid white;
546 | color: var(--gray-800);
547 | }
548 | }
549 |
550 | @media (hover: hover) {
551 | input[type="submit"]:hover,
552 | input[type="reset"]:hover,
553 | input[type="button"]:hover,
554 | button:hover {
555 | cursor: pointer;
556 | background-color: var(--gray-800);
557 | }
558 | }
559 |
560 | @media (hover: hover) and (prefers-color-scheme: dark) {
561 | input[type="submit"]:hover,
562 | input[type="reset"]:hover,
563 | input[type="button"]:hover,
564 | button:hover {
565 | cursor: pointer;
566 | background-color: var(--gray-300);
567 | }
568 | }
569 |
570 | button:focus-visible,
571 | input[type="submit"]:focus-visible,
572 | input[type="reset"]:focus-visible,
573 | input[type="button"]:focus-visible {
574 | border-color: var(--focus-ring-color);
575 | outline: none;
576 | }
577 |
578 | /* Tables
579 | ––––––––––––––––––––––––––––––––– */
580 | table {
581 | width: 100%;
582 | border-spacing: 0;
583 | margin-bottom: 1.563rem;
584 | font-variant-numeric: tabular-nums;
585 | }
586 |
587 | th,
588 | td {
589 | padding: 0.5rem 0.5rem 0.5rem 0;
590 | margin: 0;
591 | }
592 |
593 | th {
594 | font-weight: bold;
595 | text-align: left;
596 | border-bottom: 2px solid var(--gray-300);
597 | color: var(--gray-300);
598 | }
599 |
600 | @media (prefers-color-scheme: dark) {
601 | th {
602 | border-color: var(--gray-700);
603 | color: var(--gray-700);
604 | }
605 | }
606 |
607 | td {
608 | border-bottom: 2px solid var(--gray-300);
609 | }
610 |
611 | @media (prefers-color-scheme: dark) {
612 | td {
613 | border-color: var(--gray-700);
614 | }
615 | }
616 |
617 | /* Code
618 | ––––––––––––––––––––––––––––––––– */
619 | code {
620 | background: var(--gray-100);
621 | padding: 0 0.328rem;
622 | display: inline-block;
623 | vertical-align: middle;
624 | border-radius: 10px;
625 | }
626 |
627 | @media (prefers-color-scheme: dark) {
628 | code {
629 | background-color: var(--gray-700);
630 | }
631 | }
632 |
633 | p > code {
634 | white-space: normal;
635 | }
636 |
637 | pre > code {
638 | line-height: 1.563em;
639 | display: block;
640 | padding: 1rem;
641 | white-space: pre;
642 | margin-bottom: 1.563rem;
643 | overflow: scroll;
644 | }
645 |
646 | /* Forces a new-line at the end of a code block for layout purposes. */
647 | pre > code::after {
648 | content: " ";
649 | }
650 |
651 | /* Blockquote
652 | ––––––––––––––––––––––––––––––––– */
653 | blockquote {
654 | border-left: 0.25rem solid var(--gray-100);
655 | padding: 0 1rem;
656 | margin-bottom: 1.563rem;
657 | }
658 |
659 | @media (prefers-color-scheme: dark) {
660 | blockquote {
661 | border-left: 0.25rem solid var(--gray-700);
662 | }
663 | }
664 |
665 | /* List
666 | ––––––––––––––––––––––––––––––––– */
667 | ul {
668 | margin: 0;
669 | padding: 0 1px;
670 | list-style: disc outside;
671 | }
672 |
673 | ol {
674 | list-style: decimal outside;
675 | }
676 |
677 | ol,
678 | ul {
679 | padding-left: 0;
680 | margin-top: 0;
681 | margin-bottom: 1.563rem;
682 | }
683 |
684 | li {
685 | list-style-position: inside;
686 | }
687 |
688 | /* Keyboard
689 | ––––––––––––––––––––––––––––––––– */
690 | kbd {
691 | display: inline-block;
692 | padding: 0 0.328rem;
693 | color: var(--gray-700);
694 | vertical-align: middle;
695 | background-color: var(--gray-100);
696 | border: solid 1px var(--gray-300);
697 | border-bottom: solid 2px var(--gray-500);
698 | border-radius: 5px;
699 | }
700 |
701 | /* Abbreviation
702 | ––––––––––––––––––––––––––––––––– */
703 | abbr {
704 | text-decoration: none;
705 | border-bottom: 2px dashed var(--gray-600);
706 | }
707 |
708 | @media (hover: hover) {
709 | abbr:hover {
710 | cursor: help;
711 | }
712 | }
713 |
714 | .error {
715 | font-size: 12px;
716 | color: var(--red-600);
717 | margin-top: 0.25rem;
718 | }
719 |
720 | @media (prefers-color-scheme: dark) {
721 | .error {
722 | color: var(--red-400);
723 | }
724 | }
725 |
726 | button:disabled {
727 | opacity: 0.5;
728 | cursor: not-allowed !important;
729 | }
730 |
731 | button + button {
732 | margin-left: 0.5rem;
733 | }
734 |
735 | button.secondary,
736 | button[type="reset"] {
737 | background-color: var(--gray-300);
738 | border: 2px solid var(--gray-300);
739 | color: var(--gray-900);
740 | }
741 |
742 | button.secondary:hover,
743 | button[type="reset"]:hover {
744 | background-color: var(--gray-400);
745 | }
746 |
747 | /* custom */
748 | input[type="email"],
749 | input[type="text"],
750 | input[type="number"],
751 | textarea,
752 | select {
753 | width: 400px;
754 | }
755 |
756 | label {
757 | margin-top: 1rem;
758 | }
759 |
760 | button[type="submit"] {
761 | display: block;
762 | margin-top: 1em;
763 | text-align: center;
764 | }
765 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import Navi from './layouts/Navi';
3 | import Dashboard from './layouts/Dashboard';
4 | import {Grid} from 'semantic-ui-react';
5 | import Footer from './layouts/Footer';
6 |
7 |
8 |
9 | function App() {
10 | return (
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 |
27 | export default App;
28 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 | import 'semantic-ui-css/semantic.min.css';
7 | import { BrowserRouter } from 'react-router-dom';
8 |
9 | ReactDOM.render(
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/layouts/Dashboard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import ChoosingSignInMethod from '../pages/ChoosingSignInMethod'
4 | import ChoosingSignUpMethod from '../pages/ChoosingSignUpMethod'
5 | import EmployerList from '../pages/Employers/EmployerList'
6 | import JobList from '../pages/Jobs/JobList'
7 | import JobPositionList from '../pages/JobPositionList'
8 | import JobSeekerList from '../pages/JobSeekers/JobSeekerList'
9 | import { Route } from 'react-router'
10 | import EmployerSignUpPage from '../pages/Employers/EmployerSignUpPage'
11 | import JobAddPage from '../pages/Employers/JobAddPage'
12 | import SystemUserSignUpPage from '../pages/SystemUsers/SystemUserSignUpPage'
13 | import JobConfirmationPanel from '../pages/SystemUsers/JobConfirmationPanel'
14 | import JobSeekerSignUpPage from '../pages/JobSeekers/JobSeekerSignUpPage'
15 | import MainPage from '../pages/MainPage'
16 | import JobSeekerDetail from '../pages/JobSeekers/JobSeekerDetail'
17 | import { ToastContainer } from "react-toastify";
18 | import EmployerDetailPage from '../pages/Employers/EmployerDetailPage'
19 | import JobDetailPage from '../pages/Jobs/JobDetailPage'
20 |
21 | export default function Dashboard() {
22 | return (
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/src/layouts/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default function Footer() {
4 | return (
5 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/src/layouts/Navi.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Dropdown, Icon, Input, Menu } from 'semantic-ui-react'
3 | import SignedIn from './SignedIn';
4 | import SignedOut from './SignedOut';
5 | import {Link} from 'react-router-dom';
6 |
7 | export default function Navi() {
8 |
9 |
10 |
11 | const [isAuthenticated, setIsAuthanticated] = useState(false)
12 |
13 | function handleSignOut(params) {
14 | setIsAuthanticated(false)
15 | }
16 |
17 | function handleSignIn(params) {
18 | setIsAuthanticated(true)
19 | }
20 |
21 |
22 | return (
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Home
32 |
33 |
36 | Jobs
37 |
38 |
41 | Job Seekers
42 |
43 |
46 | Employers
47 |
48 |
51 | Job Positions
52 |
53 |
54 |
55 |
56 |
59 |
60 | Browse
61 |
62 |
65 | Messages
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {isAuthenticated ? : }
77 |
78 |
79 |
80 |
81 |
82 | );
83 | }
84 |
--------------------------------------------------------------------------------
/src/layouts/SignedIn.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default function SignedIn() {
4 | return (
5 |
6 |
7 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/src/layouts/SignedOut.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import { useState } from 'react';
3 | import {Button} from 'semantic-ui-react';
4 | import { NavLink } from 'react-router-dom'
5 |
6 | export default function SignedOutSignedOut(params) {
7 |
8 | // const [signUpOrIn, setSignUpOrIn] = useState()
9 |
10 |
11 |
12 | return (
13 |
14 |
15 | Sign Up
16 |
17 | Sign In
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/ChoosingSignInMethod.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, Header} from 'semantic-ui-react';
3 |
4 | export default function ChoosingSignInMethod() {
5 | return (
6 |
7 |
10 |
11 | Job Seeker
12 | Employer
13 | System User
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/ChoosingSignUpMethod.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import {Button, Header} from 'semantic-ui-react';
3 | import { NavLink } from 'react-router-dom';
4 |
5 |
6 | export default function ChoosingSignUpMethod() {
7 |
8 | const [colorOfTitle, setcolorOfTitle] = useState("black")
9 |
10 | return (
11 |
12 |
13 | Sign Up As a ...
14 |
15 |
16 | setcolorOfTitle("red")} as={NavLink} to={'/signup/jobseeker' }>Job Seeker
17 | setcolorOfTitle("pink")} as={NavLink} to={'/signup/employer' }>Employer
18 | setcolorOfTitle("orange")} as={NavLink} to={'/signup/systemuser' }>System User
19 |
20 |
21 | );
22 | }
--------------------------------------------------------------------------------
/src/pages/Employers/EmployerDetailPage.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { useParams } from 'react-router';
3 | import { Table, Header, Grid, Segment,Icon, Label, Divider } from 'semantic-ui-react';
4 | import { Link } from 'react-router-dom';
5 | import EmployerService from '../../services/EmployerService';
6 |
7 | export default function EmployerDetailPage() {
8 | const { employerId } = useParams()
9 | // const history = useHistory();
10 | const [employer, setEmployer] = useState({})
11 | useEffect(() => {
12 | let employerService = new EmployerService();
13 | employerService.getEmployerById(employerId).then((result) => setEmployer(result.data.data)).catch()
14 |
15 | }, [employerId])
16 |
17 | return (
18 |
19 |
20 |
21 | {employer.webSites?.length < 1 ? null :
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Company
31 | Website
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {employer.companyName}
41 | {}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | }
54 |
55 | {employer.webSites?.length < 1 ? null :
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | BETA
65 | BETA
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | BETA
75 | BETA
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | }
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | Email
97 |
98 |
99 |
100 | Phone Number
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | )
109 | }
--------------------------------------------------------------------------------
/src/pages/Employers/EmployerList.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import EmployerService from '../../services/EmployerService'
3 | import { Table, Header, Button, Icon } from 'semantic-ui-react';
4 | import { Link } from 'react-router-dom';
5 |
6 | export default function EmployerList() {
7 |
8 | const [employers, setEmployers] = useState([])
9 | useEffect(() => {
10 | let employerService = new EmployerService();
11 |
12 | employerService.getEmployers().then((result) => setEmployers(result.data.data)).catch();
13 | }, [])
14 |
15 | return (
16 |
17 |
18 |
19 |
20 | Company Name
21 | Website(-s)
22 | Phone Number
23 | Email
24 | Joined Date
25 | Other infos
26 |
27 |
28 |
29 |
30 | {employers.map(employer => (
31 |
32 |
33 |
34 |
35 | {employer.companyName}
36 |
37 |
38 | {employer.webSites}
39 | {employer.phone}
40 | {employer.user.email}
41 | {employer.user.createdDate}
42 |
43 |
44 | Go to infos
45 |
46 |
47 |
48 |
49 |
50 |
51 | ))}
52 |
53 |
54 |
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/src/pages/Employers/EmployerSignUpPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Header, Button} from 'semantic-ui-react';
3 | import {Formik, Form, useField} from 'formik';
4 | import * as Yup from 'yup';
5 | import {useHistory} from 'react-router-dom';
6 |
7 | export default function EmployerSignUpPage() {
8 | const history = useHistory();
9 |
10 | const TextField = ({label, ...props}) => {
11 | // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
12 | // which we can spread on . We can use field meta to show an error
13 | // message if the field is invalid and it has been touched (i.e. visited)
14 | const [field, meta] = useField(props);
15 | return (
16 |
17 |
18 |
21 | {label}{' '}
22 |
23 |
24 |
25 |
26 |
27 | {meta.touched && meta.error ? (
28 |
31 | ) : null}
32 |
33 | );
34 | };
35 |
36 | return (
37 |
38 |
41 |
42 | {
50 |
51 | history.push('/employer/' + values.id);
52 | }}>
53 |
67 |
68 |
69 | );
70 | }
71 |
--------------------------------------------------------------------------------
/src/pages/Employers/JobAddPage.jsx:
--------------------------------------------------------------------------------
1 | import {Formik, Form, useField} from 'formik';
2 | import React, {useEffect, useState} from 'react';
3 | import {useHistory, useParams} from 'react-router';
4 | import JobService from '../../services/JobService';
5 | import JobPositionService from '../../services/JobPositionService';
6 | import CityService from '../../services/CityService';
7 | import WorkPlaceService from '../../services/WorkPlaceService';
8 | import WorkTimeService from '../../services/WorkTimeService';
9 | import * as Yup from 'yup';
10 | import {
11 | Button,
12 | Dropdown,
13 | Grid,
14 | Header,
15 | Label,
16 | Checkbox,
17 | } from 'semantic-ui-react';
18 |
19 | export default function JobAddPage() {
20 | let {employerId} = useParams();
21 |
22 | let jobService = new JobService();
23 | const history = useHistory();
24 |
25 | const [workTimes, setWorkTimes] = useState([]);
26 | const [workPlaces, setWorkPlaces] = useState([]);
27 | const [cities, setCities] = useState([]);
28 | const [jobPositions, setJobPositions] = useState([]);
29 |
30 | useEffect(() => {
31 | let workPlaceService = new WorkPlaceService();
32 | let workTimeService = new WorkTimeService();
33 | let cityService = new CityService();
34 | let jobPositionService = new JobPositionService();
35 |
36 | workPlaceService
37 | .getWorkPlaces()
38 | .then((result) => setWorkPlaces(result.data.data));
39 |
40 | workTimeService
41 | .getWorkTimes()
42 | .then((result) => setWorkTimes(result.data.data));
43 |
44 | cityService
45 | .getCities()
46 | .then((result) => setCities(result.data.data))
47 | .catch();
48 | jobPositionService
49 | .getJobPositions()
50 | .then((result) => setJobPositions(result.data.data))
51 | .catch();
52 | }, []);
53 |
54 | const workTimeOptions = workTimes.map((workTime, index) => ({
55 | key: index,
56 | text: workTime.workTimeName,
57 | value: workTime.id,
58 | }));
59 |
60 | const WorkPlaceOptions = workPlaces.map((workPlace, index) => ({
61 | key: index,
62 | text: workPlace.workPlaceName,
63 | value: workPlace.id,
64 | }));
65 |
66 | const CityOptions = cities.map((city, index) => ({
67 | key: index,
68 | text: city.cityName,
69 | value: city.id,
70 | }));
71 |
72 | const JobPositionOptions = jobPositions.map((jobPosition, index) => ({
73 | key: index,
74 | text: jobPosition.position_name,
75 | value: jobPosition.id,
76 | }));
77 |
78 | const InputField = ({label, ...props}) => {
79 | // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
80 | // which we can spread on . We can use field meta to show an error
81 | // message if the field is invalid and it has been touched (i.e. visited)
82 | const [field, meta] = useField(props);
83 | return (
84 |
85 |
86 |
87 | {label}
88 |
89 |
90 |
91 |
92 |
93 |
94 | {meta.touched && meta.error ? (
95 |
98 | ) : null}
99 |
100 | );
101 | };
102 |
103 | const TrueFalse = ({children, ...props}) => {
104 | // React treats radios and checkbox inputs differently other input types, select, and textarea.
105 | // Formik does this too! When you specify `type` to useField(), it will
106 | // return the correct bag of props for you -- a `checked` prop will be included
107 | // in `field` alongside `name`, `value`, `onChange`, and `onBlur`
108 | const [field, meta] = useField({...props, type: 'checkbox'});
109 | return (
110 |
111 |
112 |
113 | {meta.touched && meta.error ? (
114 |
115 | {meta.error}
116 |
117 | ) : null}
118 |
119 | );
120 | };
121 |
122 | const SelectionFields = ({label, ...props}) => {
123 | const [field, meta] = useField(props);
124 | return (
125 |
126 |
{label}
127 |
128 |
129 | {meta.touched && meta.error ? (
130 |
{meta.error}
131 | ) : null}
132 |
133 | );
134 | };
135 |
136 | const handleChangeSemantic = (prop, value, fieldName) => {
137 | prop.setFieldValue(fieldName, value);
138 | };
139 |
140 | const handleOnSubmit = (values) => {
141 | values.employerId = employerId;
142 | values.createdDate = new Date();
143 | jobService.addJob(values);
144 | alert("Job added. After system user's confirmation, it will be listed.");
145 | history.push('/');
146 | };
147 | return (
148 |
149 |
157 |
{
193 | handleOnSubmit(values);
194 | }}>
195 | {(formikprops) => (
196 |
344 | )}
345 |
346 |
347 | );
348 | }
349 |
--------------------------------------------------------------------------------
/src/pages/JobPositionList.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect, useState} from 'react';
2 | import {Table, Header} from 'semantic-ui-react';
3 | import JobPositionService from '../services/JobPositionService';
4 |
5 | export default function JobPositionList() {
6 | const [jobPositions, setJobPositions] = useState([]);
7 | useEffect(() => {
8 | let jobPositionService = new JobPositionService();
9 |
10 | jobPositionService
11 | .getJobPositions()
12 | .then((result) => setJobPositions(result.data.data))
13 | .catch();
14 | });
15 |
16 | return (
17 |
18 |
19 |
20 |
21 | Position Name
22 | Id of Position
23 |
24 |
25 |
26 | {jobPositions.map((jobPosition) => (
27 |
28 |
29 |
30 | {jobPosition.position_name}
31 |
32 |
33 |
34 | {jobPosition.id}
35 |
36 |
37 | ))}
38 |
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/src/pages/JobSeekers/JobSeekerDetail.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { useParams } from 'react-router';
3 | // import { useHistory } from 'react-router';
4 | import { Table, Header, Grid, Segment, Image, Card, Label, Divider } from 'semantic-ui-react';
5 | import JobSeekerService from '../../services/JobSeekerService'
6 |
7 | export default function JobSeekerDetail() {
8 |
9 | const { jobSeekerId } = useParams()
10 | // const history = useHistory();
11 | const [jobSeeker, setJobSeeker] = useState({})
12 | useEffect(() => {
13 | let jobSeekerService = new JobSeekerService();
14 | jobSeekerService.getJobSeekerById(jobSeekerId).then((result) => setJobSeeker(result.data.data)).catch()
15 |
16 | }, [jobSeekerId])
17 |
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | {!!jobSeeker.info ? {jobSeeker.info}
: There is no informaiton about {jobSeeker.firstName + " " + jobSeeker.lastName}...
}
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {jobSeeker.attendedSchools?.length === 0 ? null :
51 |
52 |
53 |
54 |
55 |
56 |
57 | {jobSeeker.attendedSchools?.map((school) =>
58 |
59 |
60 |
61 | {school.school.schoolName}
62 | {school.dateOfStarting} - {school.dateOfGraduation}
63 |
64 |
65 |
66 |
67 |
68 | )}
69 |
70 |
71 |
72 |
73 |
74 | }
75 | {jobSeeker.languages?.length === 0 ? null :
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | Language Name
85 | Level
86 |
87 |
88 |
89 | {jobSeeker.languages?.map((language) =>
90 |
91 |
92 |
93 |
94 |
95 | {language.languageName}
96 | {language.languageLevel.levelDescription}
97 |
98 |
99 |
100 | {language.languageLevel.id}
101 |
102 | )}
103 |
104 |
105 |
106 |
107 |
108 |
109 | }
110 | {jobSeeker.workExperiences?.length === 0 ? null :
111 |
112 |
113 |
114 |
115 |
116 |
117 | {jobSeeker.workExperiences?.map((experience) =>
118 |
119 |
120 | {experience.workplaceName}
121 | {experience.startingDate} - {experience.quitDate}
122 |
123 | {experience.jobPosition.position_name}
124 |
125 |
126 |
127 | )}
128 |
129 |
130 |
131 |
132 |
133 | }
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | Email
142 |
143 | {jobSeeker.linkedInAccount}
144 |
145 | LinkedIn
146 |
147 | {jobSeeker.githubAccount}
148 |
149 | Github
150 |
151 |
152 |
153 |
154 |
155 |
156 | )
157 | }
158 |
--------------------------------------------------------------------------------
/src/pages/JobSeekers/JobSeekerList.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect, useState} from 'react';
2 | import {Table, Header, Button, Icon} from 'semantic-ui-react';
3 | import JobSeekerService from '../../services/JobSeekerService';
4 | import { Link } from 'react-router-dom';
5 |
6 | export default function JobSeekerList() {
7 | const [jobSeekers, setJobSeekers] = useState([]);
8 | useEffect(() => {
9 | let jobSeekerService = new JobSeekerService();
10 | jobSeekerService
11 | .getJobSeekers()
12 | .then((result) => setJobSeekers(result.data.data))
13 | .catch();
14 | }, []);
15 |
16 | return (
17 |
18 |
19 |
20 |
21 | images
22 | Name
23 | languages
24 | work experiences
25 | attended Schools
26 |
27 | description
28 | Other infos
29 |
30 |
31 |
32 |
33 | {jobSeekers.map((jobseeker) => (
34 |
35 |
36 | {jobseeker.images.imagePath == null ? (
37 |
38 |
39 |
40 | ) : (
41 |
42 | )}
43 |
44 |
45 |
50 | {jobseeker.firstName + ' ' + jobseeker.lastName}
51 |
52 |
53 |
54 | {jobseeker.languages.length === 0
55 | ? 'null'
56 | : jobseeker.languages.map(
57 | (language) =>
58 | language.languageName +
59 | ' level : ' +
60 | language.languageLevel.id
61 | )}
62 |
63 |
64 | {!(!!jobseeker.workExperiences)
65 | ? 'null'
66 | : jobseeker.workExperiences.map(
67 | (workExperience) =>
68 | 'Work place : ' +
69 | workExperience.workplaceName +
70 | ' Position : ' +
71 | workExperience.jobPosition.position_name
72 | )}
73 |
74 |
75 | {jobseeker.attendedSchools.length === 0
76 | ? 'null'
77 | : jobseeker.attendedSchools.map(
78 | (school) =>
79 | 'School : ' +
80 | school.school.schoolName +
81 | ' Department : ' +
82 | null
83 | )}
84 |
85 |
86 |
87 | {jobseeker.info === null
88 | ? 'nothing has been written'
89 | : jobseeker.info}
90 |
91 |
92 |
93 | Go to infos
94 |
95 |
96 |
97 |
98 |
99 |
100 | ))}
101 |
102 |
103 |
104 | );
105 | }
106 |
--------------------------------------------------------------------------------
/src/pages/JobSeekers/JobSeekerSignUpPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Header, Button} from 'semantic-ui-react';
3 | import {Formik, Form, useField} from 'formik';
4 | import * as Yup from 'yup';
5 | import {useHistory} from 'react-router-dom';
6 |
7 | export default function EmployerSignUpPage() {
8 | const history = useHistory();
9 |
10 | const TextField = ({label, ...props}) => {
11 |
12 | const [field, meta] = useField(props);
13 | return (
14 |
15 |
16 |
19 | {label}{' '}
20 |
21 |
22 |
23 |
24 |
25 | {meta.touched && meta.error ? (
26 |
29 | ) : null}
30 |
31 | );
32 | };
33 |
34 | return (
35 |
36 |
39 |
40 | {
48 | history.push('/jobseeker/' + values.id);
49 | }}>
50 |
64 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/src/pages/Jobs/JobDetailPage.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { useParams } from 'react-router';
3 | // import { useHistory } from 'react-router';
4 | import { Container, Header, Grid, Segment, List, Icon, Label, Card, Button, Divider } from 'semantic-ui-react';
5 | import JobService from '../../services/JobService'
6 | import EmployerService from '../../services/EmployerService'
7 | import { Link } from 'react-router-dom';
8 |
9 | export default function JobDetailPage() {
10 | const { jobId } = useParams()
11 | const [job, setJob] = useState({})
12 | const [employer, setEmployer] = useState({})
13 |
14 | useEffect(() => {
15 | let jobService = new JobService();
16 | jobService.getJobById(jobId).then((result) => setJob(result.data.data)).catch()
17 | }, [jobId])
18 |
19 | useEffect(() => {
20 | let employerService = new EmployerService();
21 | employerService.getEmployerById(job.employer?.id).then((result) => setEmployer(result.data.data))
22 | }, [job.employer?.id])
23 | console.log(employer)
24 |
25 |
26 | return (
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {job.jobPosition?.position_name}
35 |
36 | {"Company Name : " + employer.companyName}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Number of empty positions
46 |
47 |
48 | {job.empty_positions}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Min - Max salary
57 |
58 |
59 | {job.minimumSalary} - {job.maximumSalary}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Deadline
68 |
69 |
70 | {job.deadline}
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Location
79 |
80 |
81 | {job.city?.cityName}
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | Work Place
90 |
91 |
92 | {job.workPlace?.workPlaceName}
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | Work Time
101 |
102 |
103 | {job.workTime?.workTimeName}
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | {job.description}
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | {employer.companyName}
134 |
135 |
136 | {employer.user?.email}
137 |
138 |
139 |
140 |
141 | Go to infos
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | )
154 | }
--------------------------------------------------------------------------------
/src/pages/Jobs/JobList.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect, useState} from 'react';
2 | import {Table, Header, Button, Icon} from 'semantic-ui-react';
3 | import JobService from '../../services/JobService';
4 | import { Link } from 'react-router-dom';
5 |
6 | export default function JobList() {
7 | const [jobs, setJobs] = useState([]);
8 | useEffect(() => {
9 | let jobService = new JobService();
10 |
11 | jobService
12 | .getApprovedJobs()
13 | .then((result) => setJobs(result.data.data))
14 | .catch();
15 | }, []);
16 |
17 |
18 |
19 | return (
20 |
21 |
22 |
23 |
24 | Postion
25 | Company Name
26 | Number of Empty Position
27 | City
28 | Created date
29 | Deadline
30 | Other infos
31 |
32 |
33 |
34 |
35 | {jobs.map((job) => (
36 |
37 |
38 |
39 | {job.positionName}
40 |
41 |
42 | {job.companyName}
43 |
44 | {job.number_of_empty_positions == null
45 | ? '0'
46 | : job.number_of_empty_positions}
47 |
48 | {job.cityName}
49 | {job.createdDate}
50 | {job.deadLine}
51 |
52 |
53 | Go to Detail
54 |
55 |
56 |
57 |
58 |
59 |
60 | ))}
61 |
62 |
63 |
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/src/pages/MainPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default function MainPage() {
4 | return (
5 |
6 |
7 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/src/pages/SignInPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button, Divider, Form, Grid, Segment} from 'semantic-ui-react';
3 |
4 | export default function SignInModal() {
5 |
6 |
7 | return (
8 |
9 |
10 |
11 |
12 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Or
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/src/pages/SystemUsers/JobConfirmationPanel.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect, useState} from 'react';
2 | import JobService from '../../services/JobService';
3 | import ActivationPanelService from '../../services/ActivationPanelService';
4 | import {
5 | Button,
6 | Checkbox,
7 | Segment,
8 | Table,
9 | Header,
10 | Icon,
11 | Input,
12 | } from 'semantic-ui-react';
13 | import {useParams} from 'react-router-dom';
14 |
15 | export default function JobConfirmationPanel() {
16 |
17 | let jobService = new JobService();
18 | let activationPanelService = new ActivationPanelService();
19 | let {systemUserId} = useParams();
20 |
21 | const [unapprovedJobs, setUnapprovedJobs] = useState([]);
22 | useEffect(() => {
23 | let jobService = new JobService();
24 | jobService
25 | .getUnapprovedJobs()
26 | .then((result) => {
27 | setUnapprovedJobs(result.data.data);
28 | })
29 | .catch();
30 | }, []);
31 |
32 | const [approvedJobs, setApprovedJobs] = useState([]);
33 | useEffect(() => {
34 | let jobService = new JobService();
35 | jobService
36 | .getApprovedJobs()
37 | .then((result) => {
38 | setApprovedJobs(result.data.data);
39 | })
40 | .catch();
41 | }, []);
42 |
43 | function handleOnClickApprove() {
44 | unapprovedJobs.forEach((job) => {
45 | if (document.getElementById(job.id.toString() + 'checkbox').checked) {
46 | let panelForJob = {};
47 | panelForJob.jobId = job.id;
48 | panelForJob.detail = document.getElementById('detailInput').value;
49 | panelForJob.systemUserId = systemUserId;
50 | activationPanelService.setApproved(panelForJob);
51 | }
52 | });
53 | window.location.reload();
54 | }
55 | function handleOnClickApproveAll() {
56 | unapprovedJobs.forEach((job) => {
57 | let panelForJob = {};
58 | panelForJob.jobId = job.id;
59 | panelForJob.detail = document.getElementById('detailInput').value;
60 | panelForJob.systemUserId = systemUserId;
61 | activationPanelService.setApproved(panelForJob);
62 | });
63 | window.location.reload();
64 | }
65 | function handleOnClickDelete() {
66 | unapprovedJobs.forEach((job) => {
67 | if (document.getElementById(job.id.toString() + 'checkbox').checked) {
68 | jobService.deleteJob(job.id);
69 | }
70 | });
71 | window.location.reload();
72 | }
73 | function handleOnClickUnapprove() {
74 | approvedJobs.forEach((job) => {
75 | if (document.getElementById(job.id.toString() + 'checkbox').checked) {
76 | let panelForJob = {};
77 | panelForJob.jobId = job.id;
78 | panelForJob.detail = document.getElementById('detailInput').value;
79 | panelForJob.systemUserId = systemUserId;
80 | activationPanelService.setUnapproved(panelForJob);
81 | }
82 | });
83 | window.location.reload();
84 | }
85 |
86 |
87 | return (
88 |
89 |
90 |
91 |
92 | Jobs Pending Approval
93 |
94 |
95 |
96 |
97 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | Approved Jobs
179 |
180 |
181 |
182 |
183 |
252 |
253 |
254 |
255 |
256 | );
257 | }
258 |
--------------------------------------------------------------------------------
/src/pages/SystemUsers/SystemUserSignUpPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Header, Button} from 'semantic-ui-react';
3 | import {Formik, Form, useField} from 'formik';
4 | import * as Yup from 'yup';
5 | import {useHistory} from 'react-router-dom';
6 |
7 | export default function SystemUserSignUpPage() {
8 | const history = useHistory();
9 |
10 | const TextField = ({label, ...props}) => {
11 | // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
12 | // which we can spread on . We can use field meta to show an error
13 | // message if the field is invalid and it has been touched (i.e. visited)
14 | const [field, meta] = useField(props);
15 | return (
16 |
17 |
18 |
21 | {label}{' '}
22 |
23 |
24 |
25 |
26 |
27 | {meta.touched && meta.error ? (
28 |
31 | ) : null}
32 |
33 | );
34 | };
35 |
36 | return (
37 |
38 |
41 |
42 | {
50 |
51 | history.push('/systemuser/' + values.id);
52 | }}>
53 |
67 |
68 |
69 | );
70 | }
71 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/services/ActivationPanelService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class ActivationPanelService {
4 | setApproved(panelForJob) {
5 | return axios.post("http://localhost:8080/api/activationpanel/setapproved",panelForJob);
6 | }
7 | setUnapproved(panelForJob) {
8 | return axios.post("http://localhost:8080/api/activationpanel/setunapproved",panelForJob);
9 | }
10 | }
--------------------------------------------------------------------------------
/src/services/CityService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class CityService {
4 | getCities() {
5 | return axios.get("http://localhost:8080/api/cities/getAll");
6 | }
7 | }
--------------------------------------------------------------------------------
/src/services/EmployerService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class EmployerService {
4 | getEmployers() {
5 | return axios.get("http://localhost:8080/api/employers/getall");
6 | }
7 |
8 | getEmployerById(id) {
9 | return axios.get("http://localhost:8080/api/employers/getbyid?id="+id)
10 | }
11 | }
--------------------------------------------------------------------------------
/src/services/JobPositionService.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export default class JobPositionService {
4 | getJobPositions() {
5 | return axios.get('http://localhost:8080/api/jobpositions/getall');
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/services/JobSeekerService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class JobSeekersService {
4 | getJobSeekers() {
5 | return axios.get("http://localhost:8080/api/jobseekers/getall");
6 | }
7 |
8 | getJobSeekerById(id){
9 |
10 | return axios.get("http://localhost:8080/api/jobseekers/getbyid?id="+id)
11 | }
12 | }
--------------------------------------------------------------------------------
/src/services/JobService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class JobService {
4 | getJobs() {
5 | return axios.get("http://localhost:8080/api/jobs/getall");
6 | }
7 | addJob(job) {
8 | return axios.post("http://localhost:8080/api/jobs/add",job)
9 | }
10 |
11 | deleteJob(id) {
12 | return axios.post("http://localhost:8080/api/jobs/delete?id="+id)
13 | }
14 |
15 | getApprovedJobs() {
16 | return axios.get("http://localhost:8080/api/jobs/getallapprovedjobs");
17 | }
18 |
19 | getUnapprovedJobs() {
20 | return axios.get("http://localhost:8080/api/jobs/getallunapprovedjobs");
21 | }
22 |
23 | setActive(id){
24 | return axios.post("http://localhost:8080/api/jobs/setactivetojobvisibility?id="+id)
25 | }
26 |
27 | getJobById(id){
28 | return axios.get("http://localhost:8080/api/jobs/getjobbyid?id="+id);
29 | }
30 | }
--------------------------------------------------------------------------------
/src/services/WorkPlaceService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class WorkPlaceService {
4 | getWorkPlaces() {
5 | return axios.get("http://localhost:8080/api/workplaces/getall");
6 | }
7 | }
--------------------------------------------------------------------------------
/src/services/WorkTimeService.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default class WorkTimeService {
4 | getWorkTimes() {
5 | return axios.get("http://localhost:8080/api/worktimes/getall");
6 | }
7 | }
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/store/configureStore.js:
--------------------------------------------------------------------------------
1 | import { createStore } from "redux";
2 | import { devToolsEnhancer } from "redux-devtools-extension";
3 | import rootReducer from './rootReducer'
4 |
5 | export function configureStore(){
6 | return createStore(rootReducer,devToolsEnhancer())
7 | }
--------------------------------------------------------------------------------
/src/store/rootReducer.js:
--------------------------------------------------------------------------------
1 |
2 | import { combineReducers } from "redux";
3 |
4 |
5 | const rootReducer=combineReducers({
6 |
7 | })
8 |
9 | export default rootReducer;
--------------------------------------------------------------------------------