Skip to content

Commit 5a62838

Browse files
authored
Merge pull request #83 from techstartucalgary/Bernard/JobApply
Bernard/job apply
2 parents 59f5e3a + 9f5fa5a commit 5a62838

File tree

5 files changed

+200
-167
lines changed

5 files changed

+200
-167
lines changed

frontend/src/components/CreateJobModal.jsx

Lines changed: 29 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useState } from "react";
1+
import React, { useState } from "react";
22
import {
33
Button,
44
Typography,
@@ -8,66 +8,19 @@ import {
88
Slider,
99
FormControlLabel,
1010
Switch,
11-
Autocomplete,
1211
} from "@mui/material";
1312

1413
import "../styles/Modal.css";
1514

16-
const skills = ["Python", "Java", "SQL", "JavaScript", "C++", "C#", "C"];
17-
1815
function CreateJobModal(props) {
19-
const [isEditing, setIsEditing] = useState(false);
2016
const [showSalary, setShowSalary] = useState(false);
2117
const [salary, setSalary] = useState([0, 0]);
22-
const [title, setTitle] = useState("");
23-
const [description, setDescription] = useState("");
24-
const [location, setLocation] = useState("");
25-
const [company_name, setCompanyName] = useState("");
2618
const [showGenericError, setShowGenericError] = useState(false);
2719

28-
const [selectedSkills, setSelectedSkills] = useState([]);
29-
30-
useEffect(() => {
31-
if (props.job) {
32-
setIsEditing(true);
33-
setTitle(props.job.title);
34-
setDescription(props.job.description);
35-
setLocation(props.job.location);
36-
setCompanyName(props.job.company_name);
37-
if (props.job.min_salary) {
38-
setShowSalary(true);
39-
setSalary([props.job.min_salary, props.job.max_salary]);
40-
}
41-
}
42-
}, [props]);
43-
4420
const handleSalaryChange = (e, newValue) => {
4521
setSalary(newValue);
4622
};
4723

48-
const handleSkillSelection = (event, value) => {
49-
setSelectedSkills(value);
50-
};
51-
52-
const submitJobSkills = async (jobId, skills) => {
53-
await fetch(`https://chapi.techstartucalgary.com/jobs/skills/${jobId}`, {
54-
method: "POST",
55-
headers: {
56-
"Content-Type": "application/json",
57-
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
58-
},
59-
body: JSON.stringify(skills.map((skill) => ({ skill }))),
60-
})
61-
.then((response) => {
62-
if (!response.ok) {
63-
throw new Error("Skills update failed");
64-
}
65-
})
66-
.catch((error) => {
67-
console.error(error);
68-
});
69-
};
70-
7124
const submitNewJob = async (event) => {
7225
event.preventDefault();
7326
const formData = new FormData(event.target);
@@ -81,62 +34,33 @@ function CreateJobModal(props) {
8134
title,
8235
description,
8336
location,
37+
company_name,
8438
min_salary,
8539
max_salary,
86-
company_name,
87-
skills: selectedSkills.map((skill) => ({ skill })),
8840
};
8941

90-
if (isEditing) {
91-
await fetch(`https://chapi.techstartucalgary.com/jobs/${props.job.id}`, {
92-
method: "PATCH",
93-
headers: {
94-
"Content-Type": "application/json",
95-
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
96-
},
97-
body: JSON.stringify(data),
98-
})
99-
.then(async (response) => {
100-
if (!response.ok) {
101-
if (response.status === 401) {
102-
window.location.href = "#/signin";
103-
} else {
104-
setShowGenericError(true);
105-
}
106-
throw new Error("Job creation failed");
42+
await fetch("https://chapi.techstartucalgary.com/jobs", {
43+
method: "POST",
44+
headers: {
45+
"Content-Type": "application/json",
46+
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
47+
},
48+
body: JSON.stringify(data),
49+
})
50+
.then((response) => {
51+
if (!response.ok) {
52+
if (response.status === 401) {
53+
window.location.href = "#/signin";
54+
} else {
55+
setShowGenericError(true);
10756
}
108-
await submitJobSkills(props.job.id, selectedSkills);
109-
cancelModal();
110-
})
111-
.catch((error) => {
112-
console.error(error);
113-
});
114-
} else {
115-
await fetch("https://chapi.techstartucalgary.com/jobs", {
116-
method: "POST",
117-
headers: {
118-
"Content-Type": "application/json",
119-
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
120-
},
121-
body: JSON.stringify(data),
57+
throw new Error("Job creation failed");
58+
}
59+
props.closeModal();
12260
})
123-
.then(async (response) => {
124-
if (!response.ok) {
125-
if (response.status === 401) {
126-
window.location.href = "#/signin";
127-
} else {
128-
setShowGenericError(true);
129-
}
130-
throw new Error("Job creation failed");
131-
}
132-
const jobData = await response.json();
133-
await submitJobSkills(jobData.id, selectedSkills);
134-
props.closeModal();
135-
})
136-
.catch((error) => {
137-
console.error(error);
138-
});
139-
}
61+
.catch((error) => {
62+
console.error(error);
63+
});
14064
};
14165

14266
const formatCurrency = (num) => {
@@ -147,63 +71,19 @@ function CreateJobModal(props) {
14771
});
14872
};
14973

150-
const cancelModal = () => {
151-
setTitle("");
152-
setDescription("");
153-
setLocation("");
154-
setCompanyName("");
155-
setShowSalary(false);
156-
setShowGenericError(false);
157-
setSalary([0, 0]);
158-
setIsEditing(false);
159-
props.closeModal();
160-
};
161-
16274
return (
16375
<Dialog open={props.open} fullWidth>
164-
<DialogTitle>
165-
{isEditing ? "Update Existing Job" : "Create New Job"}
166-
</DialogTitle>
167-
168-
<form id="jobForm" className="form" onSubmit={submitNewJob}>
169-
<TextField
170-
name="title"
171-
label="Job Title"
172-
onChange={(e) => setTitle(e.target.value)}
173-
value={title}
174-
required
175-
/>
76+
<DialogTitle>Create New Job</DialogTitle>
77+
<form className="form" onSubmit={submitNewJob}>
78+
<TextField name="title" label="Job Title" required />
79+
<TextField name="company_name" label="Company Name" required />
17680
<TextField
17781
name="description"
17882
label="Job Description"
179-
onChange={(e) => setDescription(e.target.value)}
180-
value={description}
18183
multiline
18284
required
18385
/>
184-
<TextField
185-
name="location"
186-
label="Location"
187-
onChange={(e) => setLocation(e.target.value)}
188-
value={location}
189-
required
190-
/>
191-
<Autocomplete
192-
multiple
193-
options={skills}
194-
value={selectedSkills}
195-
onChange={handleSkillSelection}
196-
renderInput={(params) => (
197-
<TextField {...params} label="Required Skills" variant="outlined" />
198-
)}
199-
/>
200-
<TextField
201-
name="company_name"
202-
label="Company Name"
203-
onChange={(e) => setCompanyName(e.target.value)}
204-
value={company_name}
205-
required
206-
/>
86+
<TextField name="location" label="Location" required />
20787
<FormControlLabel
20888
control={
20989
<Switch
@@ -236,11 +116,9 @@ function CreateJobModal(props) {
236116
)}
237117
</div>
238118
<div className="row right-align button-container">
239-
<Button variant="outlined" onClick={cancelModal}>
240-
Cancel
241-
</Button>
119+
<Button variant="outlined" /*onClick={cancelModal}*/>Cancel</Button>
242120
<Button type="submit" variant="contained">
243-
{isEditing ? `Update Job` : `Post Job`}
121+
{/*isEditing ? `Update Job` : `Post Job`*/}
244122
</Button>
245123
</div>
246124
</form>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React, { useState } from "react";
2+
import { useEffect } from "react";
3+
import { Typography } from "@mui/material";
4+
import JobPost from "./JobPost";
5+
6+
const JobApply = () => {
7+
const [appliedJobs, setAppliedJobs] = useState([]);
8+
9+
const getAplliedJobs = async () => {
10+
await fetch("https://chapi.techstartucalgary.com/applications/me", {
11+
mode: "cors",
12+
headers: {
13+
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
14+
},
15+
})
16+
.then((response) => response.json())
17+
.then((data) => setAppliedJobs(data))
18+
.catch((error) => console.error(error));
19+
};
20+
21+
useEffect(() => {
22+
getAplliedJobs();
23+
}, []);
24+
25+
return (
26+
<div>
27+
{appliedJobs.length > 0 ? (
28+
<div>
29+
{appliedJobs.map((appliedJob) => (
30+
<JobPost
31+
key={appliedJob.id}
32+
job={appliedJob.job}
33+
disabled={true}
34+
status={appliedJob.application_status.status}
35+
/>
36+
))}
37+
</div>
38+
) : (
39+
<Typography>No found Job</Typography>
40+
)}
41+
</div>
42+
);
43+
};
44+
45+
export default JobApply;

frontend/src/components/JobPost.jsx

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import React from "react";
2+
import { useState } from "react";
23
import { Button, Typography } from "@mui/material";
4+
import { Label } from "../components/RecruiterApplicantsComponents";
35

46
import "../styles/JobPost.css";
57

68
function JobPost(props) {
9+
const [apply, setApply] = useState(false);
10+
711
const formatCurrency = (num) => {
812
return num.toLocaleString("en-US", {
913
style: "currency",
@@ -12,6 +16,51 @@ function JobPost(props) {
1216
});
1317
};
1418

19+
const getStatusColor = (status) => {
20+
switch (status) {
21+
case "SUBMITTED":
22+
return "success";
23+
case "UNDER REVIEW":
24+
return "info";
25+
case "UNDERGOING FURTHER SCREENING":
26+
return "warning";
27+
case "REJECTED":
28+
return "error";
29+
case "OFFER SENT":
30+
return "offerSent";
31+
default:
32+
return "secondary";
33+
}
34+
};
35+
36+
const applyHandler = async () => {
37+
setApply(true);
38+
try {
39+
const response = await fetch(
40+
`https://chapi.techstartucalgary.com/applications/${props.job.id}`,
41+
{
42+
method: "POST",
43+
mode: "cors",
44+
headers: {
45+
"Content-Type": "application/json",
46+
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
47+
},
48+
},
49+
);
50+
if (response.ok) {
51+
alert("Job was succesful");
52+
setApply(false);
53+
window.location.reload();
54+
} else {
55+
throw new Error("Job application failed. Please try again later");
56+
}
57+
} catch (error) {
58+
console.error(error);
59+
alert(error.message);
60+
setApply(false);
61+
}
62+
};
63+
1564
return (
1665
<div className="jobContainer">
1766
<Typography className="jobTitle">{props.job.title}</Typography>
@@ -37,9 +86,23 @@ function JobPost(props) {
3786
</Typography>
3887
);
3988
})}
40-
<Button variant="contained" className="applyButton">
41-
<Typography>Apply</Typography>
42-
</Button>
89+
{!props.disabled ? (
90+
<Button
91+
variant="contained"
92+
href=""
93+
className="applyButton"
94+
disabled={apply}
95+
onClick={applyHandler}
96+
>
97+
{apply ? (
98+
<Typography>Applying...</Typography>
99+
) : (
100+
<Typography>Apply</Typography>
101+
)}
102+
</Button>
103+
) : (
104+
<Label color={getStatusColor(props.status)}>{props.status}</Label>
105+
)}
43106
</div>
44107
);
45108
}

0 commit comments

Comments
 (0)