Skip to content

Commit f198589

Browse files
authored
Merge branch 'main' into inhwa/refine_desc
2 parents 8ba9f15 + 5e17715 commit f198589

10 files changed

+2227
-659
lines changed

package-lock.json

+1,924-482
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@
99
"axios": "^1.7.7",
1010
"eslint": "^8.40.0",
1111
"eslint-plugin-react": "^7.32.2",
12-
"react": "^18.3.1",
12+
13+
"husky": "^9.1.6",
14+
"react": "^18.2.0",
15+
1316
"react-dom": "^18.2.0",
17+
"react-dropzone": "^14.2.6",
1418
"react-scripts": "5.0.1",
1519
"web-vitals": "^2.1.0"
1620
},
@@ -44,11 +48,6 @@
4448
},
4549
"devDependencies": {
4650
"eslint-config-prettier": "^8.8.0",
47-
"husky": "^8.0.0",
48-
"lint-staged": "^13.0.0",
4951
"prettier": "2.8.8"
50-
},
51-
"lint-staged": {
52-
"**/*": "prettier --write --ignore-unknown"
5352
}
5453
}

src/App.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { useState } from "react";
22
import "./App.css";
3-
import AddSkillForm from "./components/skills/AddSkillForm";
4-
import SkillView from "./components/skills/SkillView";
5-
import SkillEditPage from "./components/skills/SkillEditPage";
3+
import User from "./components/User/page";
4+
import EducationEditPage from "./components/education/EducationEditPage";
65
import EducationForm from "./components/education/EducationForm";
76
import EducationView from "./components/education/EducationView";
8-
import EducationEditPage from "./components/education/EducationEditPage";
9-
import ExperienceForm from "./components/experience/ExperienceForm";
10-
import ViewExperience from "./components/experience/ViewExperience";
11-
import User from "./components/User/page";
7+
8+
import AddSkillForm from "./components/skills/AddSkillForm";
9+
import SkillEditPage from "./components/skills/SkillEditPage";
10+
import SkillView from "./components/skills/SkillView";
11+
1212

1313
function App() {
1414
const [showEducationForm, setShowEducationForm] = useState(false);
@@ -141,4 +141,4 @@ function App() {
141141
);
142142
};
143143

144-
export default App;
144+
export default App;

src/App.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,4 @@ describe("ExperienceForm", () => {
223223
expect(mockSubmit).not.toHaveBeenCalled();
224224
});
225225
});
226+

src/Reorder/Reorder.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from "react";
2+
3+
function Reorder({ index, reorderObj, children }) {
4+
return (
5+
<div
6+
draggable
7+
onDragStart={() => (reorderObj.onCardRef.current = index)}
8+
onDragEnter={() => (reorderObj.overCardRef.current = index)}
9+
onDragEnd={reorderObj.handleSwap}
10+
onDragOver={(e) => e.preventDefault()}
11+
>
12+
{children}
13+
</div>
14+
);
15+
}
16+
17+
export default Reorder;

src/Reorder/useReorder.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { useRef, useState } from "react";
2+
3+
const useReorder = (items, setItems, sectionType) => {
4+
const onCardRef = useRef(0);
5+
const overCardRef = useRef(0);
6+
const timeoutRef = useRef(null);
7+
const [response, setResponse] = useState(null);
8+
const [error, setError] = useState(null);
9+
10+
const handleSwap = () => {
11+
if (timeoutRef.current) {
12+
clearTimeout(timeoutRef.current);
13+
}
14+
15+
const updatedItems = [...items];
16+
const temp = updatedItems[onCardRef.current];
17+
updatedItems[onCardRef.current] = updatedItems[overCardRef.current];
18+
updatedItems[overCardRef.current] = temp;
19+
20+
setItems(updatedItems);
21+
22+
timeoutRef.current = setTimeout(() => {
23+
handleRequest(sectionType);
24+
}, 3000);
25+
};
26+
27+
const handleRequest = async (sectionType) => {
28+
// sectionType must be a valid resume section, e.g. education, experience, skills
29+
30+
const baseURL = "http://localhost:5000/resume/";
31+
try {
32+
const response = await fetch(`${baseURL}${sectionType}`, {
33+
method: "PUT",
34+
headers: {
35+
"Content-Type": "application/json",
36+
},
37+
body: JSON.stringify({ data: items }),
38+
});
39+
40+
if (!response.ok)
41+
throw new Error(`HTTP error! Status: ${response.status}`);
42+
43+
const data = await response.json();
44+
setResponse(data);
45+
setError(null);
46+
} catch (error) {
47+
setError(error);
48+
console.error(error);
49+
}
50+
};
51+
52+
return {
53+
response,
54+
error,
55+
reorderObj: { handleSwap, onCardRef, overCardRef },
56+
};
57+
};
58+
59+
export default useReorder;

src/components/Dropzone.jsx

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, { useCallback, useState } from "react";
2+
import { useDropzone } from "react-dropzone";
3+
4+
const Dropzone = () => {
5+
const [files, setFiles] = useState([]);
6+
const [rejected, setRejected] = useState([]);
7+
const onDrop = useCallback((acceptedFiles, rejectedFiles) => {
8+
if (acceptedFiles?.length) {
9+
setFiles((previousFiles) => [
10+
...previousFiles,
11+
...acceptedFiles.map((file) =>
12+
Object.assign(file, { preview: URL.createObjectURL(file) })
13+
),
14+
]);
15+
}
16+
17+
if (rejectedFiles?.length) {
18+
setRejected((previousFiles) => [...previousFiles, ...rejectedFiles]);
19+
}
20+
}, []);
21+
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
22+
23+
return (
24+
<form>
25+
<div {...getRootProps()}>
26+
<input {...getInputProps()} />
27+
{isDragActive ? (
28+
<p>Drop the files here ...</p>
29+
) : (
30+
<p>Drag 'n' drop some files here, or click to select files</p>
31+
)}
32+
</div>
33+
{/* Preview */}
34+
<ul>
35+
{files.map((file) => (
36+
<li key={file.name}>{file.name}</li>
37+
))}
38+
</ul>
39+
</form>
40+
);
41+
};
42+
export default Dropzone;

src/components/education/EducationForm.jsx

+15-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, { useState, useRef, useEffect } from "react";
22
import RefineDescription from "../../RefineDescription";
3+
import { useState } from "react";
4+
import Dropzone from "../Dropzone";
35

46
function ExperienceForm({ onSubmit, onCancel }) {
57
const [formData, setFormData] = useState({
@@ -160,19 +162,20 @@ function ExperienceForm({ onSubmit, onCancel }) {
160162
/>
161163
Current Job
162164
</label>
163-
164165
<label className="fullWidth">
165-
Description:
166-
<textarea
167-
name="description"
168-
value={formData.description}
169-
onChange={handleChange}
170-
style={{ width: '100%', height: '100px' }}
171-
/>
172-
<RefineDescription
173-
description={formData.description}
174-
setDescription={(refinedDescription) => setFormData(prev => ({ ...prev, description: refinedDescription }))}
175-
/>
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+
/>
177+
<h2>Logo</h2>
178+
<Dropzone/>
176179
</label>
177180

178181
<div className="buttonRow">

src/components/skills/SkillEditPage.jsx

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useEffect, useState } from "react";
2+
import Dropzone from "../Dropzone";
23
import "./SkillEditPage.css";
34

45
function SkillEditPage() {
@@ -135,14 +136,8 @@ function SkillEditPage() {
135136
/>
136137
</div>
137138
<div className="form-field">
138-
<label htmlFor="logo">Logo URL:</label>
139-
<input
140-
id="logo"
141-
name="logo"
142-
value={formData.logo}
143-
onChange={handleInputChange}
144-
required
145-
/>
139+
<label htmlFor="logo">Logo:</label>
140+
<Dropzone/>
146141
</div>
147142
<button
148143
type="submit"

0 commit comments

Comments
 (0)