Changeset 4d97b63 for jobvista-frontend/src/views/applications
- Timestamp:
- 08/30/24 15:44:27 (3 months ago)
- Branches:
- main
- Parents:
- 0f0add0
- Location:
- jobvista-frontend/src/views/applications
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
jobvista-frontend/src/views/applications/ApplicationDetailsModal.js
r0f0add0 r4d97b63 17 17 import Roles from "../../enumerations/Roles"; 18 18 import {ApplicationActions} from "../../redux/actions/applicationActions"; 19 import {notifyJobAdApply, notifyJobAdUpdate} from "../../utils/toastUtils"; 19 20 20 21 … … 25 26 const auth = useSelector(state => state.auth.currentUser) 26 27 const [resumeUrl, setResumeUrl] = useState(""); 28 const [additionalFileUrls, setAdditionalFileUrls] = useState([]); 27 29 28 //const [resumeFile, setResumeFile] = useState(null);30 const [additionalFiles, setAdditionalFiles] = useState(null); 29 31 const toggleModal = () => { 30 32 setModal(!modal); 31 33 }; 34 35 const {register, handleSubmit, control, formState: {errors}} = useForm(); 32 36 33 37 useEffect(() => { … … 36 40 if (success) { 37 41 setResumeUrl(response); 42 43 if (application.additionalFileNames.length > 0) { 44 ApplicationActions.downloadAdditionalFiles(application.id, (success2, response) => { 45 if (success2) { 46 setAdditionalFileUrls(response); 47 } 48 }) 49 } 38 50 } 39 51 }) 40 52 } 41 53 }, []) 54 55 const updateApplication = async () => { 56 try { 57 const formData = new FormData(); 58 if (additionalFiles && additionalFiles.length > 0) { 59 for (let i = 0; i < additionalFiles.length; i++) { 60 formData.append('additionalFiles', additionalFiles[i]); 61 } 62 } 63 64 dispatch(ApplicationActions.updateApplication(application.id, formData, (success) => { 65 if (success) { 66 toggleModal() 67 window.location.reload() 68 } 69 })) 70 } catch (err) { 71 console.error(err) 72 } 73 } 42 74 43 75 function getFileName(path) { … … 50 82 51 83 return (<div className="modal-wrap"> 52 <button onClick={toggleModal} className="application-button">View application</button> 84 {auth.role === Roles.RECRUITER ? <button onClick={toggleModal} className="application-button">View 85 application</button> : (application.status === "UNDER_REVIEW" && application.response.length > 0 && additionalFileUrls.length === 0) ? 86 <button onClick={toggleModal} className="application-button">Update application</button> : 87 <button onClick={toggleModal} className="application-button">View application</button>} 88 53 89 <Modal open={modal} onClose={toggleModal} center> 54 90 <div className="head-modal"> … … 58 94 59 95 <div className="modal-content"> 60 <form >96 <form onSubmit={handleSubmit(updateApplication)}> 61 97 <div className="row"> 62 <div className="col-md-6"> 63 <label className="label">Why are you interested in joining our company?</label> 64 <textarea disabled type="text" defaultValue={application.questionAnswers[0]} disabled 65 placeholder="Write your answer here..." className="application-textarea"/> 66 <br/><br/> 67 <label className="label">What makes you a good fit for this position?</label> 68 <textarea disabled type="text" defaultValue={application.questionAnswers[1]} 69 placeholder="Write your answer here..." className="application-textarea"/> 70 <br/><br/> 71 <label className="label">What do you hope to achieve in your first 6 months in this 72 role?</label> 73 <textarea disabled type="text" defaultValue={application.questionAnswers[2]} 74 placeholder="Write your answer here..." className="application-textarea"/> 98 <div className="col-md-6 d-flex flex-column gap-4"> 99 <div> 100 <label className="label">Why are you interested in joining our company?</label> 101 <textarea disabled type="text" defaultValue={application.questionAnswers[0]} disabled 102 placeholder="Write your answer here..." className="application-textarea"/> 103 </div> 104 105 <div> 106 <label className="label">What makes you a good fit for this position?</label> 107 <textarea disabled type="text" defaultValue={application.questionAnswers[1]} 108 placeholder="Write your answer here..." className="application-textarea"/> 109 </div> 110 111 <div> 112 <label className="label">What do you hope to achieve in your first 6 months in this 113 role?</label> 114 <textarea disabled type="text" defaultValue={application.questionAnswers[2]} 115 placeholder="Write your answer here..." className="application-textarea"/> 116 </div> 117 75 118 76 119 </div> 77 <div className="col-md-6"> 78 <label htmlFor="start">Curriculum vitae (CV)</label> 79 <br/> 80 <a className="resume-link" href={resumeUrl} target="_blank" 81 rel="noopener noreferrer">{getFileName(application.fileName)}</a> 82 <br/> 120 <div className="col-md-6 d-flex flex-column gap-4"> 121 <div> 122 <label className="label" htmlFor="start">Curriculum vitae (CV)</label> 83 123 84 <br/> 85 <label className="label">Message to the recruiter</label> 86 <textarea disabled type="text" defaultValue={application.message} placeholder="Optional..." 87 className="application-textarea"/> 124 <a className="resume-link" href={resumeUrl} target="_blank" 125 rel="noopener noreferrer">{getFileName(application.fileName)}</a> 126 </div> 127 128 <div> 129 <label className="label">Message to the recruiter</label> 130 <textarea disabled type="text" defaultValue={application.message} 131 placeholder="Optional..." 132 className="application-textarea"/> 133 </div> 134 135 136 {additionalFileUrls.length > 0 ? (<div> 137 <label className="label" htmlFor="start">Additional documents</label> 138 <ul style={{listStyleType: "none", padding: 0, margin: 0}}> 139 {additionalFileUrls.map((url, index) => ( 140 <li style={{marginBottom: 10}} key={index}> 141 <a href={url} className="resume-link" download target="_blank"> 142 {getFileName(url)} 143 </a> 144 </li>))} 145 </ul> 146 </div>) : (<div> 147 {(application.status === "UNDER_REVIEW" && application.response.length > 0 && auth.role == Roles.JOBSEEKER) && 148 <div> 149 <label className="label" htmlFor="start">Additional documents</label> 150 <input 151 className="resume-link" 152 onChange={(e) => setAdditionalFiles(e.target.files)} 153 required type="file" 154 id="fileUpload" 155 accept=".pdf" 156 multiple 157 /> 158 </div>} 159 </div> 160 )} 161 88 162 89 163 </div> 90 164 </div> 165 {(additionalFileUrls.length === 0 && application.status === "UNDER_REVIEW" && application.response.length > 0 && auth.role == Roles.JOBSEEKER) && 166 <div className="modal-buttons"> 167 <div className="cancel-btn" onClick={toggleModal}> Cancel</div> 168 <button className="submit-btn"> Submit</button> 169 </div>} 91 170 92 171 </form> 172 173 93 174 </div> 94 175 </Modal> -
jobvista-frontend/src/views/applications/Applications.css
r0f0add0 r4d97b63 17 17 } 18 18 19 /*.application-title span {*/ 20 /* font-weight: bold;*/ 21 /* */ 22 /*}*/ 19 .response-message { 20 background-color: floralwhite; 21 border-radius: 8px; 22 padding: 15px; 23 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 24 } 25 26 27 28 29 .application-card-wrapper { 30 margin: 15px 0; 31 display: flex; 32 flex-direction: column; 33 transition: all 0.4s ease-in-out; 34 gap: 3px; 35 } 36 37 .application-card.changed { 38 background-color: aliceblue; 39 } 40 41 .application-card-wrapper .expand-section { 42 max-height: 0; 43 opacity: 0; 44 transition: 0.5s ease; 45 display: flex; 46 flex-direction: column; 47 align-items: flex-end; 48 margin: 0 !important; 49 } 50 51 .application-card-wrapper.expanded .expand-section { 52 max-height: 200px; 53 opacity: 1; 54 transform: translateY(0); 55 margin-top: 10px; 56 /* transition: max-height 0.3s ease, opacity 0.3s ease, transform 0.3s ease;*/ 57 } 58 59 .expand-section textarea { 60 width: 100%; 61 padding: 10px; 62 border-radius: 8px; 63 border: 1px solid #ccc; 64 } 65 23 66 24 67 .application-card { … … 29 72 transition: all 0.3s ease; 30 73 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 31 height: auto;74 /*height: auto;*/ 32 75 padding: 20px 20px; 33 76 display: flex; 34 /*justify-content: center;*/35 /*gap: 20px;*/36 margin: 15px 0;37 /*z-index: -1000;*/38 77 } 39 78 .application-card .app-job-seeker-pic { … … 51 90 52 91 .application-card .app-info { 53 width: 6 5%;92 width: 60%; 54 93 display: inline-flex; 55 94 flex-direction: column; … … 86 125 87 126 .application-card .app-status { 88 width: 28%;127 width: 38%; 89 128 display: inline-flex; 90 129 justify-content: end; … … 98 137 } 99 138 100 . status {139 .app-status .status { 101 140 color: white; 102 141 padding: 5px 10px; … … 105 144 text-align: center; 106 145 } 146 147 148 149 150 151 107 152 108 153 … … 168 213 transform: rotate(-10deg); 169 214 } 215 216 .application-filters { 217 gap: 15px; 218 border-radius: 8px; 219 background-color: white; 220 } 221 222 /* Default Span Styles */ 223 .application-filters span { 224 padding: 8px 12px; 225 border-radius: 5px; 226 color: rgba(1,38,90,0.9); 227 cursor: pointer; 228 display: inline-flex; 229 align-items: center; 230 } 231 232 /* Icon Styles */ 233 .application-filters span i { 234 margin-right: 5px; 235 } 236 237 /* Hover Effect */ 238 .application-filters span:hover { 239 background-color: rgba(1,38,90,0.9); 240 color: white; 241 } 242 243 .application-filters span:hover i { 244 color: inherit; /* Makes the icon inherit the color from the parent span */ 245 } 246 247 /* Selected State */ 248 .application-filters span.selected { 249 background-color: rgba(1,38,90,0.9); 250 color: white; 251 } 252 253 .application-filters span.selected i { 254 color: inherit; /* Ensures icon color matches the selected state */ 255 } -
jobvista-frontend/src/views/applications/ApplicationsByJobAd.js
r0f0add0 r4d97b63 25 25 const [jobAdTitle, setJobAdTitle] = useState(""); 26 26 27 const [changedApplications, setChangedApplications] = useState({}); 28 27 29 useEffect(() => { 28 if(!dispatched && (applicationsByJobAdState.length === 0 || applicationsByJobAdState.length === 1)) {30 if(!dispatched) { 29 31 dispatch(ApplicationActions.fetchApplicationsByJobAdId(advertisement_id, (success, reponse) => { 30 32 if (success && reponse.data.length > 0) { … … 60 62 }, [dispatched]) 61 63 64 62 65 const fetchProfilePic = (jobSeekerId) => { 63 66 dispatch(JobSeekerActions.downloadProfilePic(jobSeekerId, (success, response) => { … … 67 70 })) 68 71 } 69 70 72 71 73 const options = [ … … 76 78 ]; 77 79 80 const [selectedFilter, setSelectedFilter] = useState('All'); 81 82 const filters = [ 83 { value: 'ALL', label: 'All', icon: 'fa-folder-open' }, 84 { value: 'PROPOSED', label: 'Proposed', icon: 'fa-paper-plane' }, 85 { value: 'UNDER_REVIEW', label: 'Under Review', icon: 'fa-file-pen' }, 86 { value: 'ACCEPTED', label: 'Accepted', icon: 'fa-user-check' }, 87 { value: 'DENIED', label: 'Denied', icon: 'fa-user-slash' }, 88 ]; 89 90 const filterApplicationsByJobAdvertisement = (filter) => { 91 dispatch(ApplicationActions.filterApplicationsByJobAdId(advertisement_id, filter, (success, response) => { 92 if(success) { 93 //notify 94 } 95 })) 96 } 97 78 98 let handleDefaultStatus = (status) => { 79 99 return options.find(option => option.value === status); 80 100 } 81 101 82 let handleChangeStatus = (selectedOption, id) => { 83 dispatch(ApplicationActions.updateApplicationStatus(id, selectedOption.value, (success, response) => { 102 let handleStatusChange = (selectedOption, id) => { 103 104 const currentApplication = applicationsByJobAd.find(app => app.id === id); 105 106 setChangedApplications(prevState => ({ 107 ...prevState, 108 [id]: { 109 ...prevState[id], 110 response: (selectedOption.value === "ACCEPTED" || selectedOption.value === "DENIED") ? (prevState[id]?.response || currentApplication.response || "") : "", 111 status: selectedOption.value 112 } 113 })) 114 115 setApplicationsByJobAd(prevState => ( 116 prevState.map(application => 117 application.id === id ? {...application, status: selectedOption.value} : application) 118 )) 119 120 const responseTextarea = document.getElementById(`response-${id}`); 121 if (responseTextarea) { 122 responseTextarea.value = ""; 123 } 124 125 /* dispatch(ApplicationActions.updateApplicationStatus(id, selectedOption.value, (success, response) => { 84 126 if(success) { 85 // console.log("Status updated.")86 127 notifyAppStatusUpdate() 87 128 } 88 })) 89 } 129 }))*/ 130 } 131 132 let handleResponseChange = (e, id) => { 133 134 const currentApplication = applicationsByJobAd.find(app => app.id === id); 135 136 setChangedApplications(prevState => ({ 137 ...prevState, 138 [id]: { 139 ...prevState[id], 140 response: e.target.value, 141 status: prevState[id]?.status || currentApplication.status, 142 } 143 } 144 )) 145 } 146 147 const handleSaveChanges = () => { 148 console.log(changedApplications) 149 const changes = Object.entries(changedApplications).map( 150 ([applicationId, change]) => ({ 151 id: applicationId, 152 status: change.status, 153 response: change.response, 154 }) 155 ); 156 console.log(changes) 157 158 if(changes.length === 0) { 159 return; 160 } 161 162 dispatch(ApplicationActions.updateApplications(changes, (success, response) => { 163 if(success) { 164 setChangedApplications({}); 165 notifyAppStatusUpdate() 166 //notify change success 167 } 168 })) 169 170 171 } 172 173 const isChangedApplication = (id) => { 174 return changedApplications && Object.keys(changedApplications).includes(id.toString()); 175 }; 90 176 91 177 … … 98 184 </div> 99 185 186 <div className="row"> 187 <div className="col-md-6 application-filters-wrap"> 188 <div className="application-filters d-inline-flex flex-row justify-content-start"> 189 { 190 filters.map(filter => ( 191 <span 192 key={filter.label} 193 className={selectedFilter === filter.label ? "selected" : ""} 194 onClick={() => { 195 setSelectedFilter(filter.label) 196 filterApplicationsByJobAdvertisement(filter.value) 197 setChangedApplications({}); 198 }} 199 ><i className={`fa-solid ${filter.icon}`}></i> {filter.label}</span> 200 )) 201 } 202 </div> 203 204 </div> 205 <div className="col-md-6 d-inline-flex flex-row justify-content-end"> 206 <button onClick={handleSaveChanges} 207 className={`blue-submit-button ${Object.keys(changedApplications).length === 0 ? 'disabled' : ''}`} 208 disabled={Object.keys(changedApplications).length === 0} 209 >Submit Changes</button> 210 </div> 211 </div> 212 213 214 100 215 {applicationsByJobAd && applicationsByJobAd.map((application, index) => ( 101 <div className="application-card"> 102 <div className="app-job-seeker-pic"> 103 <img 104 // loading gif 105 src={profilePicsState[application.jobSeekerId]} 106 alt="" 107 width={75} height={75} 108 /> 109 </div> 110 <div className="app-info"> 111 <span>Submitted on <b>{new Date(application.submittedOn).toLocaleString('default', { 112 day: 'numeric', 113 month: 'long', 114 year: 'numeric' 115 })}</b></span> 116 <div className="contact-info"> 117 <div className="contact-item"> 118 <i className="fa-solid fa-user"></i> <span>{application.jobSeekerName}</span> 119 </div> <div className="contact-item"> 120 <i className="fa-solid fa-envelope"></i> <span>{application.jobSeekerEmail}</span> 121 </div> <div className="contact-item"> 122 <i className="fa-solid fa-phone"></i> <span>{application.jobSeekerPhoneNumber}</span> 216 <div 217 key={application.id} 218 className={`application-card-wrapper ${(application.status !== "PROPOSED" ) ? 'expanded' : ''}`} 219 > 220 221 <div className={`application-card ${changedApplications[application.id] ? 'changed' : ''}`}> 222 <div className="app-job-seeker-pic"> 223 <img 224 src={profilePicsState[application.jobSeekerId]} 225 alt="" 226 width={75} height={75} 227 /> 228 </div> 229 <div className="app-info"> 230 <span>Submitted on <b>{new Date(application.submittedOn).toLocaleString('default', { 231 day: 'numeric', 232 month: 'long', 233 year: 'numeric' 234 })}</b></span> 235 <div className="contact-info"> 236 <div className="contact-item"> 237 <i className="fa-solid fa-user"></i> <span>{application.jobSeekerName}</span> 238 </div> 239 <div className="contact-item"> 240 <i className="fa-solid fa-envelope"></i> <span>{application.jobSeekerEmail}</span> 241 </div> 242 <div className="contact-item"> 243 <i className="fa-solid fa-phone"></i> <span>{application.jobSeekerPhoneNumber}</span> 244 </div> 245 </div> 246 </div> 247 248 <div className="app-status"> 249 <ApplicationDetailsModal application={application} /> 250 <div className="select"> 251 <Select options={options} onChange={(selectedOption) => handleStatusChange(selectedOption, application.id)} defaultValue={handleDefaultStatus(application.status)} /> 123 252 </div> 124 253 </div> 125 254 </div> 126 255 127 <div className="app-status"> 128 <ApplicationDetailsModal application={application}/> 129 <div className="select"> 130 <Select options={options} onChange={(selectedOption) => handleChangeStatus(selectedOption, application.id)} defaultValue={handleDefaultStatus(application.status)}/> 131 </div> 132 256 <div className="expand-section"> 257 <textarea 258 id={`response-${application.id}`} 259 placeholder={application.status === "UNDER_REVIEW" ? "Request additional documents..." :"Write your response..."} 260 defaultValue={application.response} 261 onChange={(e) => handleResponseChange(e, application.id)} 262 /> 133 263 </div> 134 264 </div> 135 ))} 265 ))} 266 136 267 137 268 </div>) -
jobvista-frontend/src/views/applications/ApplicationsByJobSeeker.js
r0f0add0 r4d97b63 22 22 23 23 24 25 24 useEffect(() => { 26 if (!dispatched && (applicationsByJobSeekerState.length === 0 || applicationsByJobSeekerState.length === 1)) {25 if (!dispatched && (applicationsByJobSeekerState.length === 0 || applicationsByJobSeekerState.length === 1)) { 27 26 dispatch(ApplicationActions.fetchApplicationsByJobSeeker(auth.id, (success, response) => { 28 if (success && response.data.length > 0) {27 if (success && response.data.length > 0) { 29 28 setApplicationsByJobSeeker(sortElementsBy(response.data, "submittedOn")); 30 29 } … … 41 40 useEffect(() => { 42 41 43 if (dispatched && !logoDispatched) {42 if (dispatched && !logoDispatched) { 44 43 applicationsByJobSeeker.forEach(jobAd => { 45 if (jobAd.recruiterId && !logos[jobAd.recruiterId]) {44 if (jobAd.recruiterId && !logos[jobAd.recruiterId]) { 46 45 fetchLogo(jobAd.recruiterId); 47 46 } … … 49 48 setLogoDispatched(true) 50 49 console.log("Fetch all logos GET") 51 } else if (logoDispatched) {50 } else if (logoDispatched) { 52 51 setLogos(logosState) 53 52 console.log("Fetch all logos STATE") … … 58 57 59 58 60 61 59 const fetchLogo = (recruiterId) => { 62 60 dispatch(RecruiterActions.downloadLogo(recruiterId, (success, response) => { 63 if (success) {61 if (success) { 64 62 setLogos(prevLogos => ({...prevLogos, [recruiterId]: response})) 65 63 } … … 67 65 }; 68 66 69 const options = [ 70 {value: 'PROPOSED', label: <span className="status" style={{backgroundColor: '#4A90E2'}}><i className="fa-solid fa-paper-plane"></i> Proposed</span>}, 71 {value: 'UNDER_REVIEW', label: <span className="status" style={{backgroundColor: '#F5A623'}}><i className="fa-solid fa-file-pen"></i> Under Review</span>}, 72 {value: 'ACCEPTED', label: <span className="status" style={{backgroundColor: '#7ED321'}}><i className="fa-solid fa-user-check"></i> Accepted</span>}, 73 {value: 'DENIED', label: <span className="status" style={{backgroundColor: '#D0021B'}}><i className="fa-solid fa-user-slash"></i> Denied</span>} 67 const options = [{ 68 value: 'PROPOSED', label: <span className="status" style={{backgroundColor: '#4A90E2'}}><i 69 className="fa-solid fa-paper-plane"></i> Proposed</span> 70 }, { 71 value: 'UNDER_REVIEW', label: <span className="status" style={{backgroundColor: '#F5A623'}}><i 72 className="fa-solid fa-file-pen"></i> Under Review</span> 73 }, { 74 value: 'ACCEPTED', label: <span className="status" style={{backgroundColor: '#7ED321'}}><i 75 className="fa-solid fa-user-check"></i> Accepted</span> 76 }, { 77 value: 'DENIED', label: <span className="status" style={{backgroundColor: '#D0021B'}}><i 78 className="fa-solid fa-user-slash"></i> Denied</span> 79 }]; 80 81 const [selectedFilter, setSelectedFilter] = useState('All'); 82 83 const filters = [ 84 { value: 'ALL', label: 'All', icon: 'fa-folder-open' }, 85 { value: 'PROPOSED', label: 'Proposed', icon: 'fa-paper-plane' }, 86 { value: 'UNDER_REVIEW', label: 'Under Review', icon: 'fa-file-pen' }, 87 { value: 'ACCEPTED', label: 'Accepted', icon: 'fa-user-check' }, 88 { value: 'DENIED', label: 'Denied', icon: 'fa-user-slash' }, 74 89 ]; 90 91 const filterApplicationsByJobSeeker= (filter) => { 92 dispatch(ApplicationActions.filterApplicationsByJobSeeker(auth.id, filter, (success, response) => { 93 if(success) { 94 //notify 95 } 96 })) 97 } 75 98 76 99 let handleDefaultValue = (status) => { … … 79 102 80 103 81 82 return ( 83 <div className="custom-container"> 104 return (<div className="custom-container"> 84 105 85 106 <div className="application-title"> 86 107 <h3>Application history</h3> 87 108 </div> 109 110 <div className="application-filters d-inline-flex flex-row justify-content-start"> 111 { 112 filters.map(filter => ( 113 <span 114 key={filter.label} 115 className={selectedFilter === filter.label ? "selected" : ""} 116 onClick={() => { 117 setSelectedFilter(filter.label) 118 filterApplicationsByJobSeeker(filter.value) 119 }} 120 ><i className={`fa-solid ${filter.icon}`}></i> {filter.label}</span> 121 )) 122 } 123 </div> 124 88 125 {applicationsByJobSeeker && applicationsByJobSeeker.map((application, index) => ( 89 <div key={index} className="application-card"> 90 <div className="app-company-logo"> 91 <img 92 // loading gif 93 src={logosState[application.recruiterId]} 94 alt="" 95 width={75} height={75} 96 /> 97 </div> 126 <div className="application-card-wrapper"> 127 <div key={index} className="application-card"> 128 <div className="app-company-logo"> 129 <img 130 // loading gif 131 src={logosState[application.recruiterId]} 132 alt="" 133 width={75} height={75} 134 /> 135 </div> 98 136 99 <div className="app-info"> 100 <Link to={`/job-advertisements/${application.jobAdId}`} className="jobAd-title">{application.jobAdTitle}</Link> 101 {/*<h5 className="jobAd-title"></h5>*/} 102 <div className="contact-info"> 103 <div className="contact-item"> 104 <i className="fa-solid fa-building"></i> <span>{application.recruiterName}</span> 137 <div className="app-info"> 138 <Link to={`/job-advertisements/${application.jobAdId}`} 139 className="jobAd-title">{application.jobAdTitle}</Link> 140 {/*<h5 className="jobAd-title"></h5>*/} 141 <div className="contact-info"> 142 <div className="contact-item"> 143 <i className="fa-solid fa-building"></i> <span>{application.recruiterName}</span> 144 </div> 145 <div className="contact-item"> 146 <i className="fa-solid fa-envelope"></i> <span>{application.recruiterEmail}</span> 147 </div> 148 <div className="contact-item"> 149 <i className="fa-solid fa-phone"></i> 150 <span>{application.recruiterPhoneNumber}</span> 151 </div> 152 <span> • Submitted on <b>{new Date(application.submittedOn).toLocaleString('default', { 153 day: 'numeric', month: 'long', year: 'numeric' 154 })}</b></span> 105 155 </div> 106 <div className="contact-item"> 107 <i className="fa-solid fa-envelope"></i> <span>{application.recruiterEmail}</span> 108 </div> 109 <div className="contact-item"> 110 <i className="fa-solid fa-phone"></i> <span>{application.recruiterPhoneNumber}</span> 111 </div> 112 <span> • Submitted on <b>{new Date(application.submittedOn).toLocaleString('default', { 113 day: 'numeric', 114 month: 'long', 115 year: 'numeric' 116 })}</b></span> 156 </div> 157 158 <div className="app-status"> 159 <ApplicationDetailsModal application={application}/> 160 <> {handleDefaultValue(application.status).label}</> 161 {/*<div className="select">*/} 162 {/* <Select isDisabled={true} options={options} />*/} 163 {/*</div>*/} 164 117 165 </div> 118 166 </div> 167 {application.response && 168 <div className="response-message"> 169 {application.response} 170 </div> 171 } 119 172 120 <div className="app-status"> 121 <ApplicationDetailsModal application={application}/> 122 <> {handleDefaultValue(application.status).label}</> 123 {/*<div className="select">*/} 124 {/* <Select isDisabled={true} options={options} />*/} 125 {/*</div>*/} 173 </div> 126 174 127 </div>128 </div>129 175 ))} 130 176 131 </div> 132 ) 177 </div>) 133 178 } -
jobvista-frontend/src/views/applications/ApplyToJobAdModal.js
r0f0add0 r4d97b63 105 105 onChange={(e) => setResumeFile(e.target.files[0])} required type="file" 106 106 id="fileUpload" accept=".pdf"/> 107 108 107 <br/> 109 108 <label className="label">Message to the recruiter</label>
Note:
See TracChangeset
for help on using the changeset viewer.