Ignore:
Timestamp:
06/09/24 14:24:03 (5 months ago)
Author:
223021 <daniel.ilievski.2@…>
Branches:
main
Children:
b248810
Parents:
19398ad
Message:

Implemented job application functionality, added job advertisement filtering and replaced text areas with editors

Location:
jobvista-frontend/src/views/job_advertisements
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • jobvista-frontend/src/views/job_advertisements/AddJobAdModal.js

    r19398ad r28b3398  
    11import React, {useState} from "react";
    22import "./Form.css";
     3
     4import { Editor } from 'primereact/editor';
    35
    46import 'react-responsive-modal/styles.css';
     
    1921export const AddJobAdModal = () => {
    2022    const [modal, setModal] = useState(false);
     23    const [text, setText] = useState("");
    2124    const dispatch = useDispatch();
    2225    const auth = useSelector(state => state.auth.currentUser)
     
    5255                    employmentStatus: values.employmentStatus.value,
    5356                }, (success, response) => {
    54                     if(success) {
     57                    if (success) {
    5558                        console.log("Job Advertisement added")
    5659                        toggleModal()
     
    6669
    6770    return (<div className="modal-wrap">
    68             <button onClick={toggleModal} className="btn-open-modal">POST ADVERTISEMENT</button>
    69             <Modal open={modal} onClose={toggleModal} center classNames="job-advertisement-modal">
    70                 <div className="head-modal">
    71                     <h3>Post Job Advertisement</h3>
    72                     <i className="fa-solid fa-x btn-close-modal" onClick={toggleModal}></i>
    73                 </div>
     71        <div className="col">
     72            <button onClick={toggleModal} className="add-new-card">
     73                <h3>+ Post Advertisement</h3>
     74            </button>
     75        </div>
     76        {/*<button onClick={toggleModal} className="btn-open-modal">POST ADVERTISEMENT</button>*/}
     77        <Modal open={modal} onClose={toggleModal} center classNames="job-advertisement-modal">
     78            <div className="head-modal">
     79                <h3>Post Job Advertisement</h3>
     80                <i className="fa-solid fa-x btn-close-modal" onClick={toggleModal}></i>
     81            </div>
    7482
    75                 <div className="modal-content">
    76                     <form onSubmit={handleSubmit(addJobAdvertisement)}>
    77                         <div className="row">
    78                             <div className="col-md-7">
     83            <div className="modal-content">
     84                <form onSubmit={handleSubmit(addJobAdvertisement)}>
     85                    <div className="row">
     86                        <div className="col-md-7">
    7987
    80                                 <label className="label">Job title:</label>
    81                                 <input type="text" {...register("title")}/>
    82                                 <p style={{color: "red"}}>{errors.title?.message}</p>
     88                            <label className="label">Job title:</label>
     89                            <input type="text" {...register("title")}/>
     90                            <p style={{color: "red"}}>{errors.title?.message}</p>
    8391
    84                                 <label className="label">Job description:</label>
    85                                 <textarea type="text" placeholder="Describe the job position and all the requirements"
    86                                           className="description-textarea" {...register("description")}/>
    87                                 <p style={{color: "red"}}>{errors.description?.message}</p>
    88                             </div>
    89 
    90                             <div className="col-md-5">
    91                                 <label className="label">Hourly rate:</label>
    92                                 <input {...register("startingSalary")}/>
    93                                 <p style={{color: "red"}}>{errors.startingSalary?.message}</p>
    94 
    95                                 <label className="label">Industry:</label>
    96                                 <Controller
    97                                     name="industry"
    98                                     control={control}
    99                                     render={({ field })  => (<Select
    100                                             {...field}
    101                                             options={industryOptions}
    102                                         />)}
    103                                 />
    104                                 <p style={{color: "red"}}>{errors.industry?.message}</p>
    105 
    106                                 <label className="label">Job type:</label>
    107                                 <Controller
    108                                     name="jobType"
    109                                     control={control}
    110                                     render={({ field }) => (<Select
    111                                             {...field}
    112                                             options={jobTypeOptions}
    113                                         />)}
    114                                 />
    115                                 <p style={{color: "red"}}>{errors.jobType?.message}</p>
    116 
    117                                 <label className="label">Employment status</label>
    118                                 <Controller
    119                                     name="employmentStatus"
    120                                     control={control}
    121                                     render={({ field }) => (<Select
    122                                             {...field}
    123                                             options={employmentStatusOptions}
    124                                         />)}
    125                                 />
    126                                 <p style={{color: "red"}}>{errors.employmentStatus?.message}</p>
    127 
    128                                 <label htmlFor="start">Active until:</label>
    129                                 <input type="date" defaultValue={minimumDate.toLocaleDateString('en-CA')}
    130                                        min={minimumDate.toLocaleDateString('en-CA')} onChange={(event) => console.log(event.target.value)}
    131                                        {...register("date")}/>
     92                            <label className="label">Job description:</label>
     93                            {/*<textarea type="text" placeholder="Describe the job position and all the requirements"*/}
     94                            {/*          className="description-textarea" {...register("description")}/>*/}
    13295
    13396
    134                             </div>
     97                            <Controller
     98                                name="description"
     99                                control={control}
     100                                render={({ field }) => (
     101                                    <Editor
     102                                        value={field.value}
     103                                        onTextChange={(e) => field.onChange(e.htmlValue)}
     104                                        style={{ height: '300px', fontSize: "16px", fontFamily: "Segoe UI" }}
     105                                    />
     106                                )}
     107                            />
     108                            <p style={{color: "red"}}>{errors.description?.message}</p>
    135109                        </div>
    136110
    137                         <div className="aligned">
    138                             <button className="submit-btn"> Submit</button>
     111                        <div className="col-md-5">
     112                            <label className="label">Hourly rate:</label>
     113                            <input {...register("startingSalary")}/>
     114                            <p style={{color: "red"}}>{errors.startingSalary?.message}</p>
     115
     116                            <label className="label">Industry:</label>
     117                            <Controller
     118                                name="industry"
     119                                control={control}
     120                                render={({field}) => (<Select
     121                                    {...field}
     122                                    options={industryOptions}
     123                                />)}
     124                            />
     125                            <p style={{color: "red"}}>{errors.industry?.message}</p>
     126
     127                            <label className="label">Job type:</label>
     128                            <Controller
     129                                name="jobType"
     130                                control={control}
     131                                render={({field}) => (<Select
     132                                    {...field}
     133                                    options={jobTypeOptions}
     134                                />)}
     135                            />
     136                            <p style={{color: "red"}}>{errors.jobType?.message}</p>
     137
     138                            <label className="label">Employment status</label>
     139                            <Controller
     140                                name="employmentStatus"
     141                                control={control}
     142                                render={({field}) => (<Select
     143                                    {...field}
     144                                    options={employmentStatusOptions}
     145                                />)}
     146                            />
     147                            <p style={{color: "red"}}>{errors.employmentStatus?.message}</p>
     148
     149                            <label htmlFor="start">Active until:</label>
     150                            <input type="date" defaultValue={minimumDate.toLocaleDateString('en-CA')}
     151                                   min={minimumDate.toLocaleDateString('en-CA')}
     152                                   onChange={(event) => console.log(event.target.value)}
     153                                   {...register("date")}/>
     154
     155
    139156                        </div>
     157                    </div>
    140158
    141                     </form>
    142                 </div>
    143             </Modal>
    144         </div>)
     159                    <div className="aligned">
     160                        <button className="submit-btn"> Submit</button>
     161                    </div>
     162
     163                </form>
     164            </div>
     165        </Modal>
     166    </div>)
    145167}
  • jobvista-frontend/src/views/job_advertisements/EditJobAdModal.js

    r19398ad r28b3398  
    1515import {useDispatch, useSelector} from "react-redux";
    1616import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions";
     17import {Editor} from "primereact/editor";
    1718
    1819
     
    8586
    8687                            <label className="label">Job description:</label>
    87                             <textarea type="text" defaultValue={jobAd.props.description} placeholder="Describe the job position and all the requirements"
    88                                       className="description-textarea" {...register("description")}/>
     88                            {/*<textarea type="text" defaultValue={jobAd.props.description} placeholder="Describe the job position and all the requirements"*/}
     89                            {/*          className="description-textarea" {...register("description")}/>*/}
     90
     91                            <Controller
     92                                name="description"
     93                                control={control}
     94                                render={({ field }) => (
     95                                    <Editor
     96                                        defaultValue={jobAd.props.description}
     97                                        value={jobAd.props.description}
     98                                        onTextChange={(e) => field.onChange(e.htmlValue)}
     99                                        style={{ height: '300px', fontSize: "16px", fontFamily: "Segoe UI" }}
     100                                    />
     101                                )}
     102                            />
     103
    89104                            <p style={{color: "red"}}>{errors.description?.message}</p>
    90105                        </div>
  • jobvista-frontend/src/views/job_advertisements/Form.css

    r19398ad r28b3398  
    1212    font-weight: 600;
    1313    float: right;
    14     margin-left: 10px;
     14    /*margin-left: 10px;*/
    1515}
    1616
     
    8787.description-textarea {
    8888    height: 285px;
     89}
    8990
     91.applictaion-textarea {
     92    height: 100px;
     93}
     94
     95.resume-link {
     96    display: block;
     97    padding: 5px 10px;
     98    width: 100%;
     99    border-radius: 3px;
     100    border: 1px solid lightgrey;
     101}
     102.custom {
     103    margin-top: 10px;
    90104}
    91105
     
    161175}
    162176
     177.ql-snow .ql-picker.ql-font {
     178    display: none;
     179}
     180.ql-toolbar.ql-snow .ql-picker-options {
     181    background-color: white;
     182}
     183.ql-snow .ql-tooltip {
     184    transform: translateX(100px) !important;
     185}
    163186
    164187
    165188
    166189
     190
  • jobvista-frontend/src/views/job_advertisements/JobAdDetails.js

    r19398ad r28b3398  
    99import {formatRelativeTime} from "../../utils/utils";
    1010import {AddJobAdModal} from "./AddJobAdModal";
     11import {ApplyToJobAdModal} from "../applications/ApplyToJobAdModal";
    1112
    1213
     
    5253
    5354                    <p><i className="fa-solid fa-money-check-dollar"></i> <span>Hourly rate: ${jobAd.startingSalary}</span></p>
    54                     <p><i className="fa-solid fa-briefcase"></i> Employment status: {jobAd.employmentStatus===EmploymentStatus.FULL_TIME ? "Full-time" : "Part-time"}</p>
     55                    <p><i className="fa-solid fa-briefcase"></i> Employment status: {jobAd.employmentStatus==="FULL_TIME" ? "Full-time" : "Part-time"}</p>
    5556                    <p><i className="fa-solid fa-calendar-days"></i> Active until: {new Date(jobAd.activeUntil).toLocaleString('default', { day: 'numeric', month: 'long',  year: 'numeric' })}</p>
    5657
     
    5960                        <p dangerouslySetInnerHTML={{ __html: jobAd.description.replace(/\n/g, "<br>") }}></p>
    6061                    )}
    61 
    62 
    63                     {role===Roles.JOBSEEKER &&
    64                         <>
    65                             {jobAd.active && <button className="card-button apply">Apply now</button> }
    66                             {!jobAd.active && <button className="card-button apply disabled">Apply now</button> }
    67                         </>
    68                     }
     62                    <ApplyToJobAdModal jobAd={jobAd} role={role}/>
    6963
    7064                </div>
     
    7670                    {/*TO DO - AFTER IMPLEMENTING FORM FOR UPDATING PERSONAL INFO*/}
    7771                    <h4>About the company</h4>
    78                     <p>As a pioneering Swiss software company, we provide innovative IT products and tailored digital solutions. We bring decades of experience in designing, developing, and implementing highly scalable, secure, and user-centric software.
     72                    <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.
    7974                        <br/><br/>
    80                         Working across the banking, payment, mobility, health, and publishing industries, we are experts at delivering seamless and secure user journeys within these privacy-driven environments. Our business-critical applications are designed to overcome complexity and drive growth.
    81                         <br/><br/>
    82                         We are based in Zurich, Switzerland, and have offices elsewhere in Europe, Asia, and the Middle East. Founded in 1996, we are a business of 800 experts, enabling our clients to create value with trusted software..
     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.
     76
    8377                    </p>
    8478                    <p><span><i className="fa-solid fa-envelope"></i> {recruiterDetails.email}</span> • <span>
  • jobvista-frontend/src/views/job_advertisements/JobAdvertisements.css

    r19398ad r28b3398  
    1 .head-job-advertisements-box {
    2     height: 10%;
    3     width: 100%;
    4     background-color: #fff;
    5     border-radius: 12px;
    6     padding: 15px 20px;
    7     margin-bottom: 20px;
    8     margin-top: 30px;
    9     height: auto;
    10 }
    11 
    12 
    13 .head-job-advertisements-box .head-component {
    14     display: inline;
    15 }
    16 
    17 
    18 .head-job-advertisements-box .search-container {
    19     position: relative;
    20     float: left;
    21 }
    22 .head-job-advertisements-box .search-container .search-input {
    23     width: 400px;
    24     display: inline;
    25     padding: 5px 30px;
    26     border-radius: 10px;
    27     margin-right: 15px;
    28 }
    29 
    30 .search-container .search-input:focus {
    31     outline-color: #6367ef;
    32 }
    33 
    34 .search-container i {
    35     left: 10px;
    36     position: absolute;
    37     top: 10px;
    38 }
    39 
    40 .item {
    41     width: 25%;
    42     display: inline-block;
    43     margin-left: 10px;
    44     float: right;
    45 }
  • jobvista-frontend/src/views/job_advertisements/JobAdvertisements.js

    r19398ad r28b3398  
    66import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions";
    77import {formatRelativeTime, sortElementsByDateCreated} from "../../utils/utils";
    8 import {dataRangeOptions, industryOptions, sortOptions} from "../selectOptions";
     8import {dataRangeOptions, industryOptions, industryOptionsFilter, sortOptions} from "../selectOptions";
    99import Select from "react-select";
    1010import {DeleteJobAdModal} from "./DeleteJobAdModal";
     
    1313import JobType from "../../enumerations/JobType";
    1414
    15 export const JobAdvertisements = () => {
     15export const JobAdvertisements = (props) => {
    1616
    1717    const dispatch = useDispatch();
     
    2121
    2222    const [role, setRole] = useState("");
    23     const [sortOrder, setSortOrder] = useState("newest");
    24     const [selectedDateRange, setSelectedDateRange] = useState("all");
     23    const [selectedSortOrder, setSelectedSortOrder] = useState("date_newest");
     24    const [selectedIndustry, setSelectedIndustry] = useState("all");
    2525    const [searchTerm, setSearchTerm] = useState("");
    2626    const [dispatched, setDispatched] = useState(false)
     
    3535    useEffect(() => {
    3636        if (!dispatched && jobAdvertisementsByRecruiterState.length === 0) {
    37             dispatch(JobAdvertisementActions.fetchJobAdvertisementsByRecruiter("deleteThis", (success, response) => {
     37            dispatch(JobAdvertisementActions.fetchJobAdvertisementsByRecruiter((success, response) => {
    3838                if (success && response.data.length > 0) {
    3939                    setJobAdvertisementsByRecruiter(sortElementsByDateCreated(response.data))
     
    4949    }, [jobAdvertisementsByRecruiterState])
    5050
     51    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                }
     61            }
     62        )
     63    }
     64
    5165    return (
    5266        <div className="container">
    53             <div className="head-job-advertisements-box">
     67            <div className="head-dashboard-box">
    5468                <div className="row">
    55                     <div className="col-md-3">
    56                         <div className="search-container head-component">
    57                             <i className="fa-solid fa-magnifying-glass blue-colored"></i>
     69                    <div className="col-md-12 filter-container">
     70                        <div className="search-container">
     71                            <i className="fa-solid fa-magnifying-glass search-icon"></i>
    5872                            <input
    5973                                className="search-input"
    6074                                type="text"
    6175                                placeholder="Search job advertisement by title..."
    62                                 //value={searchTerm}
    63                                 //onChange={event => setSearchTerm(event.target.value)}
     76                                value={searchTerm}
     77                                onChange={event => setSearchTerm(event.target.value)}
    6478                            />
    6579                        </div>
    66                     </div>
    67                     <div className="col-md-9">
    68 
    69                         <AddJobAdModal/>
     80                        <div className="sort-section item">
     81                            <Select
     82                                defaultValue={{value: "all", label: "All industries"}}
     83                                value={selectedIndustry.value}
     84                                onChange={option => setSelectedIndustry(option.value)}
     85                                options={industryOptionsFilter}
     86                                className="sort-range sort"
     87                            />
     88                        </div>
    7089                        <div className="sort-section item">
    7190                            <Select
    7291                                defaultValue={{value: "newest", label: "Date (Newest First)"}}
    73                                 //value={sortOrder.value}
    74                                 //onChange ={option => setSortOrder(option.value)}
     92                                value={selectedSortOrder.value}
     93                                onChange={option => setSelectedSortOrder(option.value)}
    7594                                options={sortOptions}
    7695                                className="sort-range sort"
    7796                            />
    7897                        </div>
    79                         <div className="date-range-section item">
    80                             <Select
    81                                 defaultValue={{value: "all", label: "Lifetime"}}
    82                                 //value={selectedDateRange.value}
    83                                 //onChange={option => setSelectedDateRange(option.value)}
    84                                 options={dataRangeOptions}
    85                                 className="date-range sort"
    86                             />
    87                         </div>
     98                        <button onClick={filterJobAdvertisements} className="btn-open-modal">Find jobs</button>
    8899                    </div>
    89100                </div>
    90101            </div>
    91102            <div className="row row-cols-1 row-cols-md-4 g-4">
     103                <AddJobAdModal/>
    92104
    93105                {jobAdvertisementsByRecruiter &&
     
    97109                                <div className="card-head">
    98110                                    <span className="hourly-salary"><b>${jobAd.startingSalary}/hr</b></span>
    99                                     <span className="job-type"> {jobAd.jobType===JobType.JOB ? "Job" : "Internship"}</span>
     111                                    <span
     112                                        className="job-type"> {jobAd.jobType === JobType.JOB ? "Job" : "Internship"}</span>
    100113                                    {!jobAd.active && <span className="expired">Expired</span>}
    101114                                    <div className="card-management-btns">
     
    106119                                <div className="card-body">
    107120                                    <h5 className="card-title">{jobAd.title}</h5>
    108                                     <span>{jobAd.industry} • <span style={{color: "black", fontWeight: "bold"}}>{formatRelativeTime(jobAd.postedOn)}</span></span>
     121                                    <span>{jobAd.industry} • <span style={{
     122                                        color: "black",
     123                                        fontWeight: "bold"
     124                                    }}>{formatRelativeTime(jobAd.postedOn)}</span></span>
    109125                                    <div className="card-info">
    110                                         <span><i className="fa-solid fa-building" style={{color: "#000000"}}></i> Company: <span style={{color: "black", fontWeight: "bold"}}>{jobAd.recruiterName}</span></span> <br/>
     126                                        <span><i className="fa-solid fa-building"
     127                                                 style={{color: "#000000"}}></i> Company: <span style={{
     128                                            color: "black",
     129                                            fontWeight: "bold"
     130                                        }}>{jobAd.recruiterName}</span></span> <br/>
    111131                                    </div>
    112132
    113133                                    <div className="aligned">
    114                                         <Link to={`/my-job-advertisements/view/${jobAd.id}`} className="card-button solo">View applications</Link>
     134                                        <Link to={`/my-job-advertisements/${jobAd.id}/applications`}
     135                                              className="card-button solo">View applications</Link>
    115136                                    </div>
    116137
Note: See TracChangeset for help on using the changeset viewer.