Ignore:
Timestamp:
08/30/24 15:44:27 (4 weeks ago)
Author:
223021 <daniel.ilievski.2@…>
Branches:
main
Parents:
0f0add0
Message:

Implemented Google login, additional file uploads, response messages and email notifications

File:
1 edited

Legend:

Unmodified
Added
Removed
  • jobvista-frontend/src/views/applications/ApplicationsByJobAd.js

    r0f0add0 r4d97b63  
    2525    const [jobAdTitle, setJobAdTitle] = useState("");
    2626
     27    const [changedApplications, setChangedApplications] = useState({});
     28
    2729    useEffect(() => {
    28         if(!dispatched && (applicationsByJobAdState.length === 0 || applicationsByJobAdState.length === 1)) {
     30        if(!dispatched) {
    2931            dispatch(ApplicationActions.fetchApplicationsByJobAdId(advertisement_id, (success, reponse) => {
    3032                if (success && reponse.data.length > 0) {
     
    6062    }, [dispatched])
    6163
     64
    6265    const fetchProfilePic = (jobSeekerId) => {
    6366        dispatch(JobSeekerActions.downloadProfilePic(jobSeekerId, (success, response) => {
     
    6770        }))
    6871    }
    69 
    7072
    7173    const options = [
     
    7678    ];
    7779
     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
    7898    let handleDefaultStatus = (status) => {
    7999        return options.find(option => option.value === status);
    80100    }
    81101
    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) => {
    84126            if(success) {
    85                 // console.log("Status updated.")
    86127                notifyAppStatusUpdate()
    87128            }
    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    };
    90176
    91177
     
    98184        </div>
    99185
     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
    100215        {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)} />
    123252                        </div>
    124253                    </div>
    125254                </div>
    126255
    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                />
    133263                </div>
    134264            </div>
    135        ))}
     265        ))}
     266
    136267
    137268    </div>)
Note: See TracChangeset for help on using the changeset viewer.