1 | import "./JobAdDetails.css"
|
---|
2 | import {useEffect, useState} from "react";
|
---|
3 | import {useDispatch, useSelector} from "react-redux";
|
---|
4 | import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions";
|
---|
5 | import {useParams} from "react-router";
|
---|
6 | import Roles from "../../enumerations/Roles";
|
---|
7 | import JobType from "../../enumerations/JobType";
|
---|
8 | import EmploymentStatus from "../../enumerations/EmploymentStatus";
|
---|
9 | import {formatRelativeTime} from "../../utils/utils";
|
---|
10 | import {AddJobAdModal} from "./AddJobAdModal";
|
---|
11 | import {ApplyToJobAdModal} from "../applications/ApplyToJobAdModal";
|
---|
12 | import {Link} from "react-router-dom";
|
---|
13 | import {RecruiterActions} from "../../redux/actions/recruiterActions";
|
---|
14 |
|
---|
15 |
|
---|
16 | export const JobAdDetails = () => {
|
---|
17 | const dispatch = useDispatch();
|
---|
18 | const [jobAd, setJobAd] = useState("")
|
---|
19 | const [recruiterDetails, setRecruiterDetails] = useState("");
|
---|
20 | const [role, setRole] = useState("")
|
---|
21 | const {id} = useParams();
|
---|
22 | const auth = useSelector(state => state.auth.currentUser);
|
---|
23 |
|
---|
24 | let logosState = useSelector(state => state.images.logos)
|
---|
25 | const [logoDispatched, setLogoDispatched] = useState(false)
|
---|
26 | const [logoView, setLogoView] = useState(null);
|
---|
27 |
|
---|
28 | useEffect(() => {
|
---|
29 | setRole(auth.role)
|
---|
30 | }, [auth])
|
---|
31 |
|
---|
32 | useEffect(() => {
|
---|
33 | if (jobAd) {
|
---|
34 | if (!logoDispatched && !logosState[jobAd.recruiterId]) {
|
---|
35 | dispatch(RecruiterActions.downloadLogo(jobAd.recruiterId, (success, response) => {
|
---|
36 | if (success) {
|
---|
37 | setLogoView(response)
|
---|
38 | setLogoDispatched(true)
|
---|
39 | }
|
---|
40 | }))
|
---|
41 | } else {
|
---|
42 | setLogoView(logosState[jobAd.recruiterId])
|
---|
43 | }
|
---|
44 |
|
---|
45 | }
|
---|
46 |
|
---|
47 | }, [jobAd])
|
---|
48 |
|
---|
49 |
|
---|
50 | useEffect(() => {
|
---|
51 | JobAdvertisementActions.fetchJobAdvertisementById(id, (success, response) => {
|
---|
52 | if (success) {
|
---|
53 | setJobAd(response.data)
|
---|
54 | JobAdvertisementActions.fetchRecruiterDetailsById(response.data.recruiterId, (successAgain, responseAgain) => {
|
---|
55 | if(successAgain) {
|
---|
56 | setRecruiterDetails(responseAgain.data)
|
---|
57 | }
|
---|
58 | })
|
---|
59 | }
|
---|
60 | });
|
---|
61 | }, [])
|
---|
62 | return (<div className="container">
|
---|
63 | <div className="row">
|
---|
64 | <div className="col-md-9">
|
---|
65 | <div className="details-wrap min-wrap">
|
---|
66 | <div className="row">
|
---|
67 | <div className="col-md-9">
|
---|
68 | <div className="title">
|
---|
69 | <h2>{jobAd.title} </h2>
|
---|
70 | <span className="job-type"> {jobAd.jobType===JobType.JOB ? "Job" : "Internship"}</span>
|
---|
71 | {!jobAd.active && <span className="expired">Expired</span>}
|
---|
72 | </div>
|
---|
73 |
|
---|
74 | <p className="details-head-info">
|
---|
75 | <span><b>{jobAd.recruiterName}</b></span> • <span>{jobAd.industry}</span> • <span>{formatRelativeTime(jobAd.postedOn)}</span>
|
---|
76 | </p>
|
---|
77 |
|
---|
78 | <p><i className="fa-solid fa-money-check-dollar"></i> <span>Hourly rate: ${jobAd.startingSalary}</span></p>
|
---|
79 | <p><i className="fa-solid fa-briefcase"></i> Employment status: {jobAd.employmentStatus==="FULL_TIME" ? "Full-time" : "Part-time"}</p>
|
---|
80 | <p><i className="fa-solid fa-calendar-days"></i> Active until: {new Date(jobAd.activeUntil).toLocaleString('default', { day: 'numeric', month: 'long', year: 'numeric' })}</p>
|
---|
81 |
|
---|
82 | </div>
|
---|
83 | <div className="col-md-3">
|
---|
84 | {jobAd.recruiterId &&
|
---|
85 | <>
|
---|
86 | <img
|
---|
87 | // loading gif
|
---|
88 | src={logosState[jobAd.recruiterId]}
|
---|
89 | alt=""
|
---|
90 | width={200} height={200}
|
---|
91 | />
|
---|
92 | </>
|
---|
93 | }
|
---|
94 |
|
---|
95 | </div>
|
---|
96 | </div>
|
---|
97 |
|
---|
98 |
|
---|
99 | <h4>About the job</h4>
|
---|
100 | {jobAd.description && (
|
---|
101 | <p dangerouslySetInnerHTML={{ __html: jobAd.description.replace(/\n/g, "<br>") }}></p>
|
---|
102 | )}
|
---|
103 | <ApplyToJobAdModal jobAd={jobAd} role={role}/>
|
---|
104 |
|
---|
105 | </div>
|
---|
106 | </div>
|
---|
107 | <div className="col-md-3">
|
---|
108 | <div className="details-wrap">
|
---|
109 | <Link className="recruiter-link" to={`/recruiters/${jobAd.recruiterId}`}>{jobAd.recruiterName} </Link>
|
---|
110 |
|
---|
111 | <h4>About the company</h4>
|
---|
112 | <p>
|
---|
113 | {recruiterDetails.companyDescription
|
---|
114 | ? recruiterDetails.companyDescription.length > 710
|
---|
115 | ? `${recruiterDetails.companyDescription.substring(0, 710)}...`
|
---|
116 | : recruiterDetails.companyDescription
|
---|
117 | : "There is no info about this company yet."
|
---|
118 | }
|
---|
119 | </p>
|
---|
120 |
|
---|
121 | <p>
|
---|
122 | <i className="fa-solid fa-envelope"></i> <span className="span-about"> {recruiterDetails.contactEmail}</span> <br/>
|
---|
123 | <i className="fa-solid fa-phone"></i> <span className="span-about"> {recruiterDetails.contactPhoneNumber}</span> <br/>
|
---|
124 | {recruiterDetails.receptionist && <><i className="fa-solid fa-user-tie"></i> <span className="span-about"> {recruiterDetails.receptionist}</span> </>}
|
---|
125 | </p>
|
---|
126 |
|
---|
127 | <div className="d-flex justify-content-center mt-4">
|
---|
128 | <Link className="card-button" to={`/recruiters/${jobAd.recruiterId}`}>Read more </Link>
|
---|
129 | </div>
|
---|
130 | </div>
|
---|
131 | </div>
|
---|
132 |
|
---|
133 | </div>
|
---|
134 |
|
---|
135 |
|
---|
136 |
|
---|
137 | </div>)
|
---|
138 | } |
---|