Skip to content

Commit cc9abb7

Browse files
authored
Merge pull request #23 from citruscai/inhwa/refine_desc
Inhwa/refine desc
2 parents 5e17715 + f198589 commit cc9abb7

File tree

5 files changed

+222
-81
lines changed

5 files changed

+222
-81
lines changed

.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
REACT_APP_OPENAI_API_KEY=your_api_key

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"@testing-library/jest-dom": "^5.14.1",
77
"@testing-library/react": "^13.0.0",
88
"@testing-library/user-event": "^13.2.1",
9+
"axios": "^1.7.7",
910
"eslint": "^8.40.0",
1011
"eslint-plugin-react": "^7.32.2",
1112

src/RefineDescription.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { useState } from 'react';
2+
import axios from 'axios';
3+
4+
const RefineDescription = ({ description, setDescription }) => {
5+
const [loading, setLoading] = useState(false);
6+
const [error, setError] = useState('');
7+
8+
const fetchRefinedDescription = async () => {
9+
setLoading(true);
10+
setError('');
11+
12+
try {
13+
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
14+
model: "gpt-3.5-turbo",
15+
messages: [{ role: "user", content: description }],
16+
max_tokens: 50,
17+
}, {
18+
headers: {
19+
'Authorization': `Bearer ${process.env.REACT_APP_OPENAI_API_KEY}`,
20+
'Content-Type': 'application/json',
21+
},
22+
});
23+
24+
// Ensure response contains choices and a message
25+
if (response.data.choices && response.data.choices.length > 0) {
26+
setDescription(response.data.choices[0].message.content);
27+
} else {
28+
throw new Error('No choices received from the API.');
29+
}
30+
} catch (err) {
31+
setError('Failed to fetch refined description. Please try again.');
32+
console.error('Error fetching refined description:', err);
33+
} finally {
34+
setLoading(false);
35+
}
36+
};
37+
38+
return (
39+
<div>
40+
{loading && <p>Loading...</p>}
41+
{error && <p style={{ color: 'red' }}>{error}</p>}
42+
<button onClick={fetchRefinedDescription} disabled={loading}>
43+
Refine Description
44+
</button>
45+
</div>
46+
);
47+
};
48+
49+
export default RefineDescription;
+164-80
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,193 @@
1+
import React, { useState, useRef, useEffect } from "react";
2+
import RefineDescription from "../../RefineDescription";
13
import { useState } from "react";
24
import Dropzone from "../Dropzone";
35

4-
const EducationForm = () => {
6+
function ExperienceForm({ onSubmit, onCancel }) {
57
const [formData, setFormData] = useState({
6-
course: "",
7-
school: "",
8+
title: "",
9+
company: "",
810
start_date: "",
911
end_date: "",
10-
grade: "",
12+
description: "",
1113
logo: "",
14+
isCurrent: false,
1215
});
1316

14-
const handleChange = (field) => (e) => {
15-
e.preventDefault();
17+
const [errors, setErrors] = useState({});
18+
19+
const modalRef = useRef();
20+
21+
const handleClickOutside = (e) => {
22+
if (modalRef.current && !modalRef.current.contains(e.target)) {
23+
onCancel(); // Close the form if clicked outside
24+
}
25+
};
26+
27+
useEffect(() => {
28+
document.addEventListener("mousedown", handleClickOutside);
29+
return () => {
30+
document.removeEventListener("mousedown", handleClickOutside);
31+
};
32+
}, []);
33+
34+
const handleChange = (e) => {
35+
const { name, value } = e.target;
36+
setFormData({ ...formData, [name]: value });
37+
};
38+
39+
const handleFileChange = (e) => {
40+
const file = e.target.files[0];
41+
if (file) {
42+
const reader = new FileReader();
43+
reader.onload = () => {
44+
setFormData({ ...formData, logo: reader.result });
45+
};
46+
reader.readAsDataURL(file);
47+
}
48+
};
1649

17-
setFormData({
18-
...formData,
19-
[field]: e.currentTarget.value,
20-
});
50+
const handleCheckboxChange = () => {
51+
setFormData((prev) => ({
52+
...prev,
53+
isCurrent: !prev.isCurrent,
54+
end_date: "",
55+
}));
56+
};
57+
58+
const validateDates = () => {
59+
if (!formData.isCurrent && formData.end_date) {
60+
if (new Date(formData.end_date) < new Date(formData.start_date)) {
61+
setErrors({ end_date: "End date cannot be earlier than start date" });
62+
return false;
63+
}
64+
}
65+
setErrors({});
66+
return true;
2167
};
2268

2369
const handleSubmit = (e) => {
2470
e.preventDefault();
2571

26-
fetch("http://127.0.0.1:5000/resume/education", {
27-
method: "POST",
28-
headers: {
29-
"Content-Type": "application/json",
30-
},
31-
body: JSON.stringify(formData),
32-
})
33-
.then((response) => response.json())
34-
.then((data) => {
35-
console.log(data);
36-
alert("Education successfully added!");
37-
})
38-
.catch((error) => {
39-
console.log(error);
40-
alert("Error: Education not added :(");
41-
});
72+
if (!validateDates()) return;
73+
74+
const experienceData = {
75+
title: formData.title,
76+
company: formData.company,
77+
start_date: formData.start_date,
78+
end_date: formData.isCurrent ? "Present" : formData.end_date,
79+
description: formData.description,
80+
logo: formData.logo,
81+
};
82+
83+
onSubmit(experienceData);
4284
};
4385

4486
return (
45-
<>
46-
<div className="education-form-container">
47-
<form onSubmit={handleSubmit}>
48-
<label>
49-
<h2>Course</h2>
50-
<input
51-
type="text"
52-
value={formData.course}
53-
placeholder="Course"
54-
onChange={handleChange("course")}
55-
/>
56-
</label>
57-
<label>
58-
<h2>School</h2>
59-
<input
60-
type="text"
61-
value={formData.school}
62-
placeholder="School"
63-
onChange={handleChange("school")}
64-
/>
65-
</label>
66-
<label>
67-
<h2>Start Date</h2>
68-
<input
69-
type="month"
70-
value={formData.start_date}
71-
placeholder="Month Year"
72-
onChange={handleChange("start_date")}
73-
/>
74-
</label>
75-
<label>
76-
<h2>End Date</h2>
77-
<input
78-
type="month"
79-
value={formData.end_date}
80-
placeholder="End Date"
81-
onChange={handleChange("end_date")}
82-
/>
83-
</label>
87+
<div className="experienceForm modal-overlay">
88+
<div className="experienceForm modal experienceModal" ref={modalRef}>
89+
<button className="close-button" onClick={onCancel}>
90+
&times;
91+
</button>
92+
93+
<form onSubmit={handleSubmit} className="experienceForm">
94+
{formData.logo && (
95+
<div className="logoPreviewContainer">
96+
<img src={formData.logo} alt="Logo" className="logoPreview" />
97+
</div>
98+
)}
99+
<div className="fileUploadContainer">
100+
<label className="fullWidth">
101+
Logo:
102+
<input type="file" name="logo" onChange={handleFileChange} />
103+
</label>
104+
</div>
105+
<div className="row">
106+
<label>
107+
Title:
108+
<input
109+
type="text"
110+
name="title"
111+
value={formData.title}
112+
onChange={handleChange}
113+
required
114+
/>
115+
</label>
116+
<label>
117+
Company:
118+
<input
119+
type="text"
120+
name="company"
121+
value={formData.company}
122+
onChange={handleChange}
123+
required
124+
/>
125+
</label>
126+
</div>
127+
128+
<div className="row">
129+
<label>
130+
Start Date:
131+
<input
132+
type="date"
133+
name="start_date"
134+
value={formData.start_date}
135+
onChange={handleChange}
136+
required
137+
/>
138+
</label>
139+
<label>
140+
End Date:
141+
<input
142+
type="date"
143+
name="end_date"
144+
value={formData.isCurrent ? "" : formData.end_date}
145+
onChange={handleChange}
146+
disabled={formData.isCurrent}
147+
/>
148+
{errors.end_date && (
149+
<span className="error" style={{ color: "red" }}>
150+
{errors.end_date}
151+
</span>
152+
)}
153+
</label>
154+
</div>
155+
84156
<label>
85-
<h2>Grade</h2>
86157
<input
87-
type="number"
88-
min="0"
89-
max="100"
90-
value={formData.grade}
91-
placeholder="Grade"
92-
onChange={handleChange("grade")}
158+
type="checkbox"
159+
name="isCurrent"
160+
checked={formData.isCurrent}
161+
onChange={handleCheckboxChange}
93162
/>
94-
%
163+
Current Job
95164
</label>
96-
<label>
165+
<label className="fullWidth">
166+
Description:
167+
<textarea
168+
name="description"
169+
value={formData.description}
170+
onChange={handleChange}
171+
style={{ width: '100%', height: '100px' }}
172+
/>
173+
<RefineDescription
174+
description={formData.description}
175+
setDescription={(refinedDescription) => setFormData(prev => ({ ...prev, description: refinedDescription }))}
176+
/>
97177
<h2>Logo</h2>
98-
<Dropzone/>
99-
178+
<Dropzone/>
100179
</label>
101180

102-
<button onSubmit={handleSubmit}>Submit Education</button>
181+
<div className="buttonRow">
182+
<button type="submit">Submit</button>
183+
<button type="button" name="cancel" onClick={onCancel}>
184+
Cancel
185+
</button>
186+
</div>
103187
</form>
104188
</div>
105-
</>
189+
</div>
106190
);
107-
};
191+
}
108192

109-
export default EducationForm;
193+
export default ExperienceForm;

src/components/experience/ExperienceForm.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState, useRef, useEffect } from "react";
2+
import RefineDescription from "../../RefineDescription";
23

34
function ExperienceForm({ onSubmit, onCancel }) {
45
const [formData, setFormData] = useState({
@@ -12,7 +13,7 @@ function ExperienceForm({ onSubmit, onCancel }) {
1213
});
1314

1415
const [errors, setErrors] = useState({});
15-
16+
1617
const modalRef = useRef();
1718

1819
const handleClickOutside = (e) => {
@@ -166,7 +167,12 @@ function ExperienceForm({ onSubmit, onCancel }) {
166167
name="description"
167168
value={formData.description}
168169
onChange={handleChange}
170+
style={{ width: '100%', height: '100px' }}
169171
/>
172+
<RefineDescription
173+
description={formData.description}
174+
setDescription={(refinedDescription) => setFormData(prev => ({ ...prev, description: refinedDescription }))}
175+
/>
170176
</label>
171177

172178
<div className="buttonRow">

0 commit comments

Comments
 (0)