Changeset befb988 for jobvista-frontend/src/views/job_advertisements
- Timestamp:
- 06/17/24 21:59:14 (5 months ago)
- Branches:
- main
- Children:
- 08f82ec
- Parents:
- b248810
- Location:
- jobvista-frontend/src/views/job_advertisements
- Files:
-
- 6 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
jobvista-frontend/src/views/job_advertisements/AddJobAdModal.js
rb248810 rbefb988 1 1 import React, {useState} from "react"; 2 import ". /Form.css";2 import "../shared_css/Modal.css"; 3 3 4 4 import { Editor } from 'primereact/editor'; … … 17 17 import {useDispatch, useSelector} from "react-redux"; 18 18 import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions"; 19 import {notifyJobAdPost} from "../../utils/toastUtils"; 19 20 20 21 … … 32 33 description: yup.string().required("Please enter a description"), 33 34 industry: yup.mixed().required("Select industry"), 34 startingSalary: yup. number().required("Please enter the starting salary"),35 startingSalary: yup.string().required("Please enter the starting salary"), 35 36 jobType: yup.mixed().required("Select job type"), 36 37 employmentStatus: yup.mixed().required("Select employment status"), … … 46 47 dispatch(JobAdvertisementActions.addJobAdvertisement( 47 48 { 48 email: auth.email,49 id: auth.id, 49 50 title: values.title, 50 51 description: values.description, … … 56 57 }, (success, response) => { 57 58 if (success) { 58 console.log("Job Advertisement added")59 // console.log("Job Advertisement added") 59 60 toggleModal() 61 notifyJobAdPost() 60 62 } 61 63 } … … 75 77 </div> 76 78 {/*<button onClick={toggleModal} className="btn-open-modal">POST ADVERTISEMENT</button>*/} 77 <Modal open={modal} onClose={toggleModal} center classNames="job-advertisement-modal">79 <Modal open={modal} onClose={toggleModal} center> 78 80 <div className="head-modal"> 79 81 <h3>Post Job Advertisement</h3> … … 82 84 83 85 <div className="modal-content"> 84 <form onSubmit={handleSubmit(addJobAdvertisement)}>86 <form> 85 87 <div className="row"> 86 88 <div className="col-md-7"> … … 111 113 <div className="col-md-5"> 112 114 <label className="label">Hourly rate:</label> 113 <input {...register("startingSalary")}/>115 <input type="number" {...register("startingSalary")}/> 114 116 <p style={{color: "red"}}>{errors.startingSalary?.message}</p> 115 117 … … 157 159 </div> 158 160 159 <div className="aligned"> 160 <button className="submit-btn"> Submit</button> 161 <div className="modal-buttons"> 162 <div className="cancel-btn" onClick={toggleModal}> Cancel</div> 163 <button className="submit-btn" onClick={handleSubmit(addJobAdvertisement)}>Submit</button> 161 164 </div> 162 165 -
jobvista-frontend/src/views/job_advertisements/DeleteJobAdModal.js
rb248810 rbefb988 1 1 import React, {useState} from "react"; 2 import ". /Form.css";2 import "../shared_css/Modal.css"; 3 3 4 4 import 'react-responsive-modal/styles.css'; … … 15 15 import {useDispatch, useSelector} from "react-redux"; 16 16 import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions"; 17 import {notifyJobAdDelete} from "../../utils/toastUtils"; 17 18 18 19 … … 29 30 dispatch(JobAdvertisementActions.deleteJobAdvertisement(jobAd.props.id, (success, response) => { 30 31 if (success) { 31 console.log("Job Advertisement deleted")32 // console.log("Job Advertisement deleted") 32 33 toggleModal() 34 notifyJobAdDelete() 33 35 } 34 36 })) -
jobvista-frontend/src/views/job_advertisements/EditJobAdModal.js
rb248810 rbefb988 1 1 import React, {useEffect, useState} from "react"; 2 import ". /Form.css";2 import "../shared_css/Modal.css"; 3 3 4 4 import 'react-responsive-modal/styles.css'; … … 16 16 import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions"; 17 17 import {Editor} from "primereact/editor"; 18 import {notifyJobAdDelete, notifyJobAdEdit} from "../../utils/toastUtils"; 18 19 19 20 … … 23 24 const auth = useSelector(state => state.auth.currentUser) 24 25 const toggleModal = () => { 26 console.log("NAD SET") 25 27 setModal(!modal); 28 console.log("POD SET") 29 26 30 }; 27 31 … … 52 56 }, jobAd.props.id, (success, response) => { 53 57 if(success) { 54 console.log("Job Advertisement edited")58 // console.log("Job Advertisement edited") 55 59 toggleModal() 60 notifyJobAdEdit() 56 61 } 57 62 } … … 78 83 79 84 <div className="modal-content"> 80 <form onSubmit={handleSubmit(editJobAdvertisement)}>85 <form> 81 86 <div className="row"> 82 87 <div className="col-md-7"> … … 92 97 name="description" 93 98 control={control} 99 defaultValue={jobAd.props.description} 94 100 render={({ field }) => ( 95 101 <Editor 96 defaultValue={jobAd.props.description}102 // defaultValue={jobAd.props.description} 97 103 value={jobAd.props.description} 98 104 onTextChange={(e) => field.onChange(e.htmlValue)} … … 107 113 <div className="col-md-5"> 108 114 <label className="label">Hourly rate:</label> 109 <input defaultValue={jobAd.props.startingSalary} {...register("startingSalary")}/>115 <input type="number" defaultValue={jobAd.props.startingSalary} {...register("startingSalary")}/> 110 116 <p style={{color: "red"}}>{errors.startingSalary?.message}</p> 111 117 … … 166 172 </div> 167 173 168 <div className="aligned"> 169 <button className="submit-btn"> Submit</button> 174 <div className="modal-buttons"> 175 <div className="cancel-btn" onClick={toggleModal}> Cancel</div> 176 <button className="submit-btn" onClick={handleSubmit(editJobAdvertisement)}> Save changes</button> 170 177 </div> 171 172 178 </form> 173 179 </div> -
jobvista-frontend/src/views/job_advertisements/JobAdDetails.css
rb248810 rbefb988 10 10 .details-wrap { 11 11 width: 100%; 12 //height: auto;13 height: 80vh;12 height: auto; 13 max-height: 80vh; 14 14 overflow-y: auto; 15 background-color: #fff; 16 border-radius: 12px; 17 padding: 15px 20px; 18 margin-bottom: 20px; 19 20 /*scrollbar-width: thin; !* "auto" hides scrollbar on some browsers, "thin" shows a thin scrollbar *!*/ 21 /*scrollbar-color: #999999 #fff;*/ 22 } 23 24 .details-wrap .span-about { 25 color: darkgray; 26 } 27 28 29 30 .details-wrap-profile { 31 width: 100%; 32 height: auto; 33 15 34 background-color: #fff; 16 35 border-radius: 12px; … … 56 75 } 57 76 77 .apply-button { 78 border: 0; 79 border-radius: 8px; 80 width: 45%; 81 background-image: linear-gradient(to right, #a1c4fd 0%, aliceblue 61%, #a1c4fd 100%); 82 background-size: 200% auto; 83 font-weight: bold; 84 padding: 5px 10px; 85 transition: 0.4s; 86 } 87 88 .apply-button:not(.disabled):hover{ 89 background-color: rgb(187, 215, 235); 90 color: black; 91 } 92 93 .disabled { 94 cursor: default !important; 95 opacity: 0.6; 96 } 97 58 98 .apply:not(.expired) { 59 99 width: 20% !important; … … 65 105 background-position: right center; 66 106 } 107 108 .recruiter-link { 109 color: black; 110 font-size: 30px; 111 text-decoration:none; 112 } -
jobvista-frontend/src/views/job_advertisements/JobAdDetails.js
rb248810 rbefb988 10 10 import {AddJobAdModal} from "./AddJobAdModal"; 11 11 import {ApplyToJobAdModal} from "../applications/ApplyToJobAdModal"; 12 import {Link} from "react-router-dom"; 13 import {RecruiterActions} from "../../redux/actions/recruiterActions"; 12 14 13 15 … … 20 22 const auth = useSelector(state => state.auth.currentUser); 21 23 24 let logosState = useSelector(state => state.images.logos) 25 const [logoDispatched, setLogoDispatched] = useState(false) 26 const [logoView, setLogoView] = useState(null); 27 22 28 useEffect(() => { 23 29 setRole(auth.role) 24 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]) 25 48 26 49 … … 41 64 <div className="col-md-9"> 42 65 <div className="details-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> 43 73 44 <div className="title"> 45 <h2>{jobAd.title} </h2> 46 <span className="job-type"> {jobAd.jobType===JobType.JOB ? "Job" : "Internship"}</span> 47 {!jobAd.active && <span className="expired">Expired</span>} 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> 48 96 </div> 49 97 50 <p className="details-head-info">51 <span><b>{jobAd.recruiterName}</b></span> • <span>{jobAd.industry}</span> • <span>{formatRelativeTime(jobAd.postedOn)}</span>52 </p>53 54 <p><i className="fa-solid fa-money-check-dollar"></i> <span>Hourly rate: ${jobAd.startingSalary}</span></p>55 <p><i className="fa-solid fa-briefcase"></i> Employment status: {jobAd.employmentStatus==="FULL_TIME" ? "Full-time" : "Part-time"}</p>56 <p><i className="fa-solid fa-calendar-days"></i> Active until: {new Date(jobAd.activeUntil).toLocaleString('default', { day: 'numeric', month: 'long', year: 'numeric' })}</p>57 98 58 99 <h4>About the job</h4> … … 66 107 <div className="col-md-3"> 67 108 <div className="details-wrap"> 68 < h3>{jobAd.recruiterName}</h3>109 <Link className="recruiter-link" to={`/recruiters/${jobAd.recruiterId}`}>{jobAd.recruiterName} </Link> 69 110 70 {/*TO DO - AFTER IMPLEMENTING FORM FOR UPDATING PERSONAL INFO*/}71 111 <h4>About the company</h4> 72 112 <p> 73 For over two decades, we have been harnessing technology to drive meaningful change. Working side by side with leading brands, we build strategies, products and solutions tailored to unique needs –regardless of industry, region or scale. By combining world-class engineering, industry expertise and a people-centric mindset, we consult and partner with our customers to create technological solutions that drive innovation and transform businesses. 74 <br/><br/> 75 From ideation to production, we support our customers with bespoke solutions across various industries, including payments, insurance, finance and banking, technology, media and entertainment, telecommunications, retail and consumer goods, supply chain and logistics, healthcare and life sciences, energy and resources, government, automotive and travel. 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> 76 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> </>} 77 125 </p> 78 <p><span><i className="fa-solid fa-envelope"></i> {recruiterDetails.email}</span> • <span> 79 <i className="fa-solid fa-phone"></i> {recruiterDetails.phoneNumber}</span> 80 </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> 81 130 </div> 82 131 </div> -
jobvista-frontend/src/views/job_advertisements/JobAdvertisements.css
rb248810 rbefb988 1 .photo-box { 2 position: relative; 3 margin-bottom: 140px; 4 } 5 6 .photo-box div img { 7 background-color: rgb(243, 242, 241); 8 } 9 10 .company-banner { 11 width: 100%; 12 height: 300px; 13 object-fit: cover; 14 object-position: initial; 15 display: block; 16 border-radius: 10px; 17 } 18 19 .company-logo { 20 position: absolute; 21 border-radius: 25px; 22 border: 5px solid rgb(243, 242, 241); 23 bottom: -110px; 24 left: 70px 25 } 26 27 .info-tab { 28 margin: 20px 10px; 29 position: absolute; 30 left: 280px; 31 font-family: Poppins; 32 } 33 34 .photo-box .edit-buttons { 35 display: flex; 36 gap: 10px; 37 position: absolute; 38 right: 20px; 39 bottom: -100px; 40 } 41 42 .edit-buttons .exclamation { 43 display: inline; 44 position: relative; 45 } 46 47 .fa-circle-exclamation { 48 color: #d80e0e; 49 50 } 51 52 .edit-buttons .modal-wrap .react-responsive-modal-modal .head-modal { 53 background-color: white !important; 54 color: black !important; 55 } 56 57 .edit-buttons button { 58 background-color: white; 59 border: none; 60 border-radius: 5px; 61 padding: 7px 13px; 62 transition: 0.1s; 63 } 64 65 .edit-buttons button:hover { 66 /*background-color: #F2F2F2;*/ 67 background-color: lightgray; 68 } 69 70 .my-workspace { 71 position: relative; 72 } 73 74 .custom-text-area { 75 height: 14rem !important; 76 } 77 78 .line-separator { 79 width: 95%; 80 border-top: 1px solid gray; 81 border-radius: 5px; 82 margin: auto; 83 margin-bottom: 30px; 84 } 85 86 87 .confirmation-bar { 88 position: fixed; 89 //top: 80px; 90 left: 0; 91 width: calc(100% - 17px); 92 background-color: rgba(0, 0, 0, 0.5); /* Adjust background color as needed */ 93 //background-color: #7D7D7A; /* Adjust background color as needed */ 94 padding: 10px; 95 z-index: 11; 96 97 } 98 .confirmation-bar-buttons { 99 display: flex; 100 justify-content: right; 101 gap: 10px; 102 margin-right: 60px 103 } 104 .confirmation-bar .confirmation-bar-buttons button { 105 padding: 5px 20px; 106 border: none; 107 border-radius: 8px; 108 color: white; 109 transition: 0.1s; 110 } 111 .confirmation-bar .confirmation-bar-buttons .cancel-changes { 112 background-color: #8D8D8B; 113 } 114 115 .confirmation-bar .confirmation-bar-buttons .cancel-changes:hover { 116 background-color: #9B9A99; 117 } 118 119 .confirmation-bar .confirmation-bar-buttons .save-changes { 120 background-color: #0866FF; 121 122 } 123 .confirmation-bar .confirmation-bar-buttons .save-changes:hover { 124 background-color: dodgerblue; 125 } 126 -
jobvista-frontend/src/views/job_advertisements/RecruiterWorkspace.js
rb248810 rbefb988 2 2 3 3 import "./JobAdvertisements.css" 4 import "../shared_css/Random.css" 5 4 6 import {useDispatch, useSelector} from "react-redux"; 5 7 import {useEffect, useState} from "react"; … … 12 14 import {Link} from "react-router-dom"; 13 15 import JobType from "../../enumerations/JobType"; 16 import {RecruiterActions} from "../../redux/actions/recruiterActions"; 14 17 15 export const JobAdvertisements = (props) => { 18 19 export const Workspace = (props) => { 16 20 17 21 const dispatch = useDispatch(); 22 const [dispatched, setDispatched] = useState(false) 23 24 const auth = useSelector(state => (state.auth.currentUser)) 25 18 26 const [jobAdvertisementsByRecruiter, setJobAdvertisementsByRecruiter] = useState([]); 19 const auth = useSelector(state => (state.auth.currentUser))20 27 let jobAdvertisementsByRecruiterState = useSelector(state => (state.jobAd.jobAdvertisementsByRecruiter)) 21 28 22 const [role, setRole] = useState(""); 29 const [recruiterDetails, setRecruiterDetails] = useState(null); 30 23 31 const [selectedSortOrder, setSelectedSortOrder] = useState("date_newest"); 24 32 const [selectedIndustry, setSelectedIndustry] = useState("all"); 25 33 const [searchTerm, setSearchTerm] = useState(""); 26 const [dispatched, setDispatched] = useState(false) 34 35 const [activeJobListingsCount, setActiveJobListingsCount] = useState(0); 36 37 useEffect(() => { 38 if (auth) { 39 dispatch(RecruiterActions.fetchRecruiterEditDetailsById(auth.id, (success, response) => { 40 if (success) { 41 setRecruiterDetails(response.data) 42 } 43 })) 44 } 45 }, [auth]); 27 46 28 47 29 48 useEffect(() => { 30 if (auth) {31 setRole(auth.role);32 }33 }, [auth]);34 35 useEffect(() => {36 49 if (!dispatched && jobAdvertisementsByRecruiterState.length === 0) { 37 dispatch(JobAdvertisementActions.fetchJobAdvertisementsByRecruiter( (success, response) => {50 dispatch(JobAdvertisementActions.fetchJobAdvertisementsByRecruiter(auth.id, (success, response) => { 38 51 if (success && response.data.length > 0) { 39 52 setJobAdvertisementsByRecruiter(sortElementsBy(response.data)) … … 46 59 setJobAdvertisementsByRecruiter(jobAdvertisementsByRecruiterState) 47 60 console.log("Fetch job advertisements by recruiter STATE") 61 62 setActiveJobListingsCount(countActiveJobListings(jobAdvertisementsByRecruiterState)); 48 63 } 64 49 65 }, [jobAdvertisementsByRecruiterState]) 50 66 51 67 let filterJobAdvertisements = () => { 52 JobAdvertisementActions.filterJobAdvertisementsByRecruiter( 53 { 54 searchTerm: searchTerm, 55 industry: selectedIndustry, 56 sortOrder: selectedSortOrder 57 }, (success, response) => { 58 if (success) { 59 setJobAdvertisementsByRecruiter(response.data); 60 } 68 JobAdvertisementActions.filterJobAdvertisementsByRecruiter({ 69 searchTerm: searchTerm, industry: selectedIndustry, sortOrder: selectedSortOrder 70 }, (success, response) => { 71 if (success) { 72 setJobAdvertisementsByRecruiter(response.data); 61 73 } 62 )74 }) 63 75 } 64 76 65 return ( 66 <div className="container"> 67 <div className="head-dashboard-box"> 77 function countActiveJobListings(jobAds) { 78 if (jobAds.length > 0) { 79 const activeJobListings = jobAds.filter(job => job.active) 80 return activeJobListings.length; 81 } 82 return 0; 83 } 84 85 return (<div className="container"> 86 87 {/*<div className="line-separator"></div>*/} 88 89 <div className="filter-container"> 68 90 <div className="row"> 69 <div className="col-md-12 filter- container">91 <div className="col-md-12 filter-box"> 70 92 <div className="search-container"> 71 93 <i className="fa-solid fa-magnifying-glass search-icon"></i> … … 96 118 /> 97 119 </div> 98 <button onClick={filterJobAdvertisements} className="b tn-open-modal">Find jobs</button>120 <button onClick={filterJobAdvertisements} className="blue-submit-button">Find jobs</button> 99 121 </div> 100 122 </div> 101 123 </div> 102 <div className="row row-cols-1 row-cols-md- 4 g-4">124 <div className="row row-cols-1 row-cols-md-5 g-3"> 103 125 <AddJobAdModal/> 104 126 105 {jobAdvertisementsByRecruiter && 106 jobAdvertisementsByRecruiter.map((jobAd, index) => ( 107 <div key={index} className="col"> 108 <div className="custom-card"> 109 <div className="card-head"> 110 <span className="hourly-salary"><b>${jobAd.startingSalary}/hr</b></span> 111 <span 112 className="job-type"> {jobAd.jobType === JobType.JOB ? "Job" : "Internship"}</span> 113 {!jobAd.active && <span className="expired">Expired</span>} 114 <div className="card-management-btns"> 115 <DeleteJobAdModal props={jobAd}/> 116 <EditJobAdModal props={jobAd}/> 117 </div> 127 {jobAdvertisementsByRecruiter && jobAdvertisementsByRecruiter.map((jobAd, index) => ( 128 <div key={index} className="col"> 129 <div className="custom-card"> 130 <div className="card-head"> 131 <span className="hourly-salary"><b>${jobAd.startingSalary}/hr</b></span> 132 <span 133 className="job-type"> {jobAd.jobType === JobType.JOB ? "Job" : "Internship"}</span> 134 {!jobAd.active && <span className="expired">Expired</span>} 135 <div className="card-management-btns"> 136 <DeleteJobAdModal props={jobAd}/> 137 <EditJobAdModal props={jobAd}/> 118 138 </div> 119 <div className="card-body">120 <h5 className="card-title">{jobAd.title}</h5>121 <span>{jobAd.industry} • <span style={{122 color: "black",123 124 125 139 </div> 140 <div className="card-body"> 141 <h5 className="card-title">{jobAd.title}</h5> 142 <span>{jobAd.industry} • <span style={{ 143 color: "black", fontWeight: "bold" 144 }}>{formatRelativeTime(jobAd.postedOn)}</span></span> 145 <div className="card-info"> 126 146 <span><i className="fa-solid fa-building" 127 147 style={{color: "#000000"}}></i> Company: <span style={{ 128 color: "black", 129 fontWeight: "bold" 148 color: "black", fontWeight: "bold" 130 149 }}>{jobAd.recruiterName}</span></span> <br/> 131 150 </div> 132 151 133 134 <Link to={`/my-job-advertisements/${jobAd.id}/applications`}135 136 152 <div className="aligned"> 153 <Link to={`/job-management-hub/applications/${jobAd.id}`} 154 className="card-button solo">View applications</Link> 155 </div> 137 156 138 </div>139 157 </div> 140 158 </div> 141 ))} 142 159 </div>))} 143 160 </div> 144 161 </div> 162 163 145 164 ) 146 165 }
Note:
See TracChangeset
for help on using the changeset viewer.