Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export pdf #19

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17,787 changes: 17,787 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"name": "orientation-project-js",
"name": "orientation-project",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"@react-pdf/renderer": "^4.0.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"eslint": "^8.40.0",
"eslint-plugin-react": "^7.32.2",
"file-saver": "^2.0.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
Expand Down Expand Up @@ -41,5 +44,15 @@
"devDependencies": {
"eslint-config-prettier": "^8.8.0",
"prettier": "2.8.8"
}
},
"jest": {
"moduleNameMapper": {
"react-pdf/dist/esm/entry.webpack": "react-pdf/dist/esm/entry.jest"
}
},
"description": "Refer to the Fellowship LMS for information!",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC"
}
15 changes: 13 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { useState } from "react";
import "./App.css";
import AddSkillModal from "./component/add_skills/AddSkillModal.jsx";
import ResumePage from "./component/exportResume/resumeTemplate.jsx";

function App() {
const [openAddSkillModal, setOpenAddSkillModal] = useState(false);

const clickAddSkill = () => {
setOpenAddSkillModal((prevState) => !prevState);
};

return (
<div className="App">
{openAddSkillModal && <AddSkillModal onClose={clickAddSkill} />}

<h1>Resume Builder</h1>
<div className="resumeSection">
<h2>Experience</h2>
Expand All @@ -19,11 +30,11 @@ function App() {
<div className="resumeSection">
<h2>Skills</h2>
<p>Skill Placeholder</p>
<button>Add Skill</button>
<button onClick={clickAddSkill}>Add Skill</button>
<br></br>
</div>
<br></br>
<button>Export</button>
<ResumePage></ResumePage>
</div>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/App.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { render, screen } from "@testing-library/react";
import App from "./App";

test("renders learn react link", () => {
test("renders Resume Builder heading", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
const headingElement = screen.getByText(/resume builder/i);
expect(headingElement).toBeInTheDocument();
});
96 changes: 96 additions & 0 deletions src/component/add_skills/AddSkillModal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
.modal-background {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.6); /* Semi-transparent dark overlay */
display: flex;
justify-content: center;
align-items: center;
z-index: 50;
}

/* Modal container */
.modal-container {
display: flex;
flex-direction: row;
background-color: white;
width: 60%; /* Adjust size as needed */
height: 60%;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); /* Adds a soft shadow */
position: relative;
color: black;
justify-content: space-between; /* Make sure both sides (left and right) are spaced evenly */
}

/* Skill description container */
.skill-description .description {
margin-bottom: 15px;
}

.description label {
font-weight: 600;
color: #333;
display: block;
margin-bottom: 5px;
}

.description textarea {
width: 60%;
height: 40px;
padding: 8px;
font-size: 0.9rem;
border-radius: 5px;
border: 1px solid #ccc;
resize: none;
transition: border-color 0.3s ease;
}

.description textarea:focus {
border-color: #007bff; /* Blue border on focus */
outline: none;
}

/* Left side - modal-content */
.modal-content {
width: 50%; /* Set width to take 50% of the modal */
padding-right: 20px;
border-right: 1px solid #ddd; /* Vertical line on the right side */
}

/* Right side - added-skill-content */
.added-skill-content {
width: 50%; /* Take up the remaining 50% of the modal */
padding-left: 20px; /* Adds some spacing from the left */
}

/* Added skills section */
.added-skills-section {
width: 100%; /* Ensure it takes up the full width of the right section */
display: flex;
flex-direction: column;
gap: 10px; /* Spacing between skill cards */
height: 70%;
/* overflow-y: scroll; */
}

.added-skill-content .added-skills-section {
flex-grow: 1;
overflow-y: scroll; /* If skills exceed the container, scroll */
}

/* Ensure the modal adapts for smaller screens */
@media (max-width: 500px) {
.modal-container {
flex-direction: column;
width: 90%;
}

.modal-content,
.added-skill-content {
width: 100%;
padding: 10px;
border-right: none; /* Remove the border on smaller screens */
border-bottom: 1px solid #ddd; /* Add border between sections on small screens */
}
}
159 changes: 159 additions & 0 deletions src/component/add_skills/AddSkillModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { useEffect, useState } from "react";
import "./AddSkillModal.css";
import AddedSkillCards from "./AddedSkillsCard";

function AddSkillModal({ onClose }) {
const [skillName, setSkillName] = useState("");
const [skillProficiency, setSkillProficiency] = useState("");
const [skillLogo, setSkillLogo] = useState("");
const [addedSkills, setAddedSkills] = useState([]);

// Fetch the current list of skills when it first load
useEffect(() => {
const fetchSkills = async () => {
const added_skill_list = getListSkills();
if (added_skill_list) {
setAddedSkills(added_skill_list);
}
};

fetchSkills();
}, []);

const getListSkills = async () => {
try {
const response = await fetch("resume/skill", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});

if (!response.ok) {
throw new Error("Failed to get skills");
}

const result = await response.json();
return result;
} catch (error) {
console.error("Error", error);
}
};

//This addSkill function will be updated for Api POst request
const addSkillHandler = async (skillData) => {
try {
const response = await fetch("/resume/skill", {
method: "POST",
body: JSON.stringify(skillData),
headers: {
"Content-Type": "application/json",
},
});

if (!response.ok) {
throw new Error("Failed to add skill");
}

const result = await response.json();
return result.id;
} catch (error) {
console.error("Error", error);
}
};

const addSkill = async () => {
const skillData = {
name: skillName,
proficiency: skillProficiency,
logo: skillLogo,
};

const result_id = await addSkillHandler(skillData);

if (!result_id) {
throw new Error("Failed to get skill id");
}

const newSkill = { ...skillData, id: result_id };
setAddedSkills((prevSkill) => [...prevSkill, newSkill]);
};

const handleSkillNameChange = (event) => {
setSkillName(event.target.value);
};

const handleSkillProficiencyChange = (event) => {
setSkillProficiency(event.target.value);
};
const handleSkillLogoChange = (event) => {
setSkillLogo(event.target.value);
};

return (
<div className="modal-background" onClick={onClose}>
<div className="modal-container" onClick={(e) => e.stopPropagation()}>
<div className="modal-content">
<h2 className="modal-title">Add New Skill</h2>
<div className="skill-description">
<div className="description">
<label htmlFor="skill-detail">Skill Name:</label>
<textarea
name="skill-detail"
id="skill-detail"
placeholder="Enter skill name"
onChange={handleSkillNameChange}
></textarea>
</div>
<div className="description">
<label htmlFor="proficient-detail">Proficiency:</label>
<textarea
name="proficient-detail"
id="proficient-detail"
placeholder="Describe proficiency"
onChange={handleSkillProficiencyChange}
></textarea>
</div>
<div className="description">
<label htmlFor="logo-url">Logo URL:</label>
<textarea
name="logo-url"
id="logo-url"
placeholder="Enter logo URL"
onChange={handleSkillLogoChange}
></textarea>
</div>
</div>
<div className="modal-buttons">
<button className="add-skill-btn" onClick={addSkill}>
Add More Skills
</button>
</div>
</div>

<div className="added-skill-content">
{/* Added skills */}
<div className="added-skills-section">
{addedSkills.length > 0
? addedSkills.map((skill, index) => (
<div key={index}>
<AddedSkillCards skill={skill} />
</div>
))
: "empty"}
</div>
<div>
<p>Added skills {addedSkills.length}</p>
</div>
<div className="modal-buttons">
<button className="submit-btn" onClick={onClose}>
Submit
</button>
</div>
</div>
</div>
</div>
);
}

export default AddSkillModal;
56 changes: 56 additions & 0 deletions src/component/add_skills/AddedSkillCards.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.skill-card {
display: flex;
position: relative;
align-items: center;
justify-content: space-between;
width: 80%; /* Ensures the card takes up the full width of the parent container */
height: 50px; /* Fixes the height of the card for uniformity */
margin: 10px auto; /* Centers the card and adds spacing between cards */
padding: 10px 15px; /* Adds padding inside the card */
background-color: #f5f5f5;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); /* Adds a soft shadow */
}

.skill-info {
display: flex;
align-items: center;
gap: 15px; /* Adds spacing between skill name, proficiency, and logo */
}

.skill-info img {
width: 40px;
height: 40px;
border-radius: 50%; /* Makes the logo circular */
}

.skill-details {
display: flex;
/* flex-direction: column; */
justify-content: center;
gap: 5px;
}

.skill-details p {
margin: 0;
font-size: 14px;
color: #333;
}

.edit-remove {
display: flex;
gap: 3px;
}

.btn {
background-color: #ff6b6b; /* Red button for remove */
border: none;
padding: 5px 10px;
color: white;
border-radius: 5px;
cursor: pointer;
}

.btn:hover {
background-color: #ff4c4c; /* Darker red on hover */
}
Loading
Loading