Skip to content

Commit

Permalink
Merge pull request #17 from aashutoshPanda/minor-fixes
Browse files Browse the repository at this point in the history
UI/UX improvements + Bug fixes
  • Loading branch information
aashutoshPanda committed Feb 10, 2024
2 parents cc60c07 + 0a21139 commit 79e8b49
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Welcome to TailorResume.AI, your ultimate solution for creating, managing, and s

## Live Applications

- **Netlify Deployment:** [tailor-my-resume.netlify.app](tailor-my-resume.netlify.app)
- **Netlify Deployment:** [tailor-resume-ai.netlify.app](https://tailor-resume-ai.netlify.app)
- **Render.com Deployment:** [tailor-my-resume-express-backend.onrender.com](https://tailor-my-resume-express-backend.onrender.com)

## Features
Expand Down
8 changes: 6 additions & 2 deletions TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
11. Guest login time extend that [DONE]
confirm about share feature

Default resume selected for job is set as null
Add floating option button with contact info
Default resume selected for job is set as null [DONE]
Add floating option button with contact info [DONE]
share resume link - undefined [DONE]
resume image max height [DONE]
Add space after Delhi, India in mobile [DONE]
Move burger icon on left side of resume input in mobile [DONE]
4 changes: 3 additions & 1 deletion client/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
REACT_ENV='LOCAL'
REACT_APP_FRONTEND_BASE_URL_PROD='https://tailor-resume-ai.netlify.app'
REACT_APP_BACKEND_BASE_URL_PROD='https://tailor-my-resume-express-backend.onrender.com'
REACT_APP_FRONTEND_BASE_URL_LOCAL='http://localhost:3000'
REACT_APP_BACKEND_BASE_URL_LOCAL='http://localhost:3030'
REACT_APP_BACKEND_BASE_URL_PROD='https://something.onrender.com'
REACT_APP_GUEST_LOGIN_TOKEN='fake.eyJpZCI6IjY1YjZjNzgzODk3N2Q5ODNiZjY1MmFhMyIsImlhdCI6MTcwNjQ3NzQ0MywiZXhwIjoxNzA2NTYzODQzfQ.KW-avQFoI51X3j-Roljs-tdS2Ib2FspDeeeRBgHWs3k'
REACT_APP_SENTRY_FRONTEND_DSN='fake://5822d4ffa1a690acdf40c5611d42d8e3@us.sentry.io/4506683019755520'
SENTRY_AUTH_TOKEN=fake=_z+/aJe70/usonXP/ipi+GX3UWCOsSpVhheAN/WjzpoI
2 changes: 2 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import store from "./store";
import { localStorageKeyAPIToken } from "./constants/api";
import wavesSVG from "../src/assets/waves.svg";
import ShareResume from "./pages/ShareResume";
import ContactChip from "./components/ContactChip";

const PrivateRoutes = () => {
const token = localStorage.getItem(localStorageKeyAPIToken); // Replace "yourTokenKey" with the actual key used to store the token
Expand All @@ -23,6 +24,7 @@ function App() {
<img src={wavesSVG} style={{ position: "fixed", bottom: "0px", zIndex: -100000000 }} alt="waves"></img>
<Provider store={store}>
<Router>
<ContactChip />
<Header />
<Routes>
{/* Redirect from / and /home to /home/resume */}
Expand Down
30 changes: 30 additions & 0 deletions client/src/components/ContactChip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from "react";
import Avatar from "@mui/material/Avatar";
import Chip from "@mui/material/Chip";
import Stack from "@mui/material/Stack";

export default function AbsolutePositionedChip() {
const chipContainerStyle = {
position: "fixed",
left: "12px",
top: "50%",
transform: "translate(-50%) rotate(-90deg)",
zIndex: 9999,
cursor: "pointer",
};

return (
<div style={chipContainerStyle}>
<Stack direction="row" spacing={1}>
<Chip
avatar={<Avatar alt="Natacha" src="https://i.ibb.co/3z8L9vN/profile-pic.jpg" />}
label="Made with ❤️ by Ashutosh Panda"
href="https://github.com/aashutoshPanda"
component="a"
variant="filled"
// color="primary"
/>
</Stack>
</div>
);
}
2 changes: 1 addition & 1 deletion client/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Header = () => {

return (
<Container maxWidth="lg">
<Grid container justifyContent={isTokenPresent ? "space-between" : "center"} alignItems="center" pt={2}>
<Grid container justifyContent={isTokenPresent ? "space-between" : "center"} alignItems="center" pt={2} pb={4}>
<Grid item>
<Box
onClick={() => navigate("/home")}
Expand Down
14 changes: 12 additions & 2 deletions client/src/components/ResumeCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ const ResumeCard = ({ resume }) => {
setSnackbarOpen(true);
}
};
const getURLToCopy = (resumeId) => {
const { REACT_APP_ENV, REACT_APP_FRONTEND_BASE_URL_LOCAL, REACT_APP_FRONTEND_BASE_URL_PROD } = process.env;
const baseURL = REACT_APP_ENV === "LOCAL" ? REACT_APP_FRONTEND_BASE_URL_LOCAL : REACT_APP_FRONTEND_BASE_URL_PROD;
const urlToCopy = `${baseURL}/resume/share/${resumeId}`;
return urlToCopy;
};

const handleShare = async (id, visibility) => {
let url = `${process.env.REACT_APP_FRONTEND_BASE_URL}/resume/share/${id}`;
try {
if (visibility !== visibilityTypes.public) {
await api.patch(`/resumes/${id}`, { visibility: visibilityTypes.public });
}
const url = getURLToCopy(id);
await copyToClipboard(url);
dispatch(updateVisibility({ id, visibility: visibilityTypes.public }));
} catch (error) {
Expand Down Expand Up @@ -102,7 +108,11 @@ const ResumeCard = ({ resume }) => {
<Typography variant="subtitle2" color="textSecondary" align="left">
Last Edited: {elapsed}
</Typography>
<img src={resume.thumbnail} alt={resume.name} style={{ width: "40%", height: "auto" }} />
<img
src={resume.thumbnail}
alt={resume.name}
style={{ width: "auto", height: "40%", maxHeight: "220px", overflow: "hidden" }}
/>
{resume.visibility === visibilityTypes.public ? visibility : null}
</CardContent>
<CardActions>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/ResumeTemplates/EntryLevel.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ const EntryLevelResumePreview = (props, ref) => {
</Grid>

{/* Second Row */}
<Grid container spacing={3}>
<Grid container spacing={3} pt={1}>
{/* First Column */}
<Grid item md={6}>
<Box textAlign="left">
<Typography variant="h6">Experience</Typography>
<Divider style={{ backgroundColor: "#f0f0f0" }} />
{experienceList.map((experience, index) => (
<Box key={index} mt={2}>
<Box key={index} mt={1}>
{/* First Row - Company Name */}
<Typography variant="subtitle1" fontWeight="bold">
{experience.organisation}
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/ResumeTemplates/Internship.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const InternshipResumePreview = (props, ref) => {
</Grid>

{/* Second Row */}
<Grid container justifyContent="center" direction="column">
<Grid container justifyContent="center" direction="column" pt={1}>
<Grid container justifyContent="center">
<Grid item>
<Typography variant="h6">Education</Typography>
Expand All @@ -132,7 +132,7 @@ const InternshipResumePreview = (props, ref) => {
<Typography variant="h6">Experience</Typography>
<Divider style={{ backgroundColor: "#f0f0f0" }} />
{experienceList.map((experience, index) => (
<Box key={index} mt={2}>
<Box key={index} mt={1}>
{/* First Row - Company Name */}
<Typography variant="subtitle1" fontWeight="bold">
{experience.organisation}
Expand Down
Empty file.
39 changes: 22 additions & 17 deletions client/src/pages/BuildResume.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,28 @@ const ResumeBuilder = () => {
const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);
const resumeName = useSelector((state) => state.resumeBuilder.selectedResume.name);
const template = useSelector((state) => state.resumeBuilder.selectedResume.template);
useEffect(() => {
const fetchById = async () => {
await dispatch(fetchResumeById(resumeId));
};
fetchById();
}, [resumeId, dispatch]);

const captureScreenshot = async (element) => {
const container = document.createElement("div");
container.style.width = "1280px";
container.style.display = "flex";
container.style.overflow = "hidden";
container.appendChild(element);
document.body.appendChild(container);
const canvas = await html2canvas(container);
document.body.removeChild(container);
return canvas.toDataURL("image/png");
};

const handleDownload = async () => {
try {
const input = ref.current;
const canvas = await html2canvas(input);
const imgData = canvas.toDataURL("image/png");
const imgData = await captureScreenshot(ref.current);
const pdf = new jsPDF();
pdf.addImage(imgData, "JPEG", 0, 0);
pdf.save(selectedResume.name);
Expand All @@ -49,31 +65,20 @@ const ResumeBuilder = () => {
}
};

useEffect(() => {
const fetchById = async () => {
await dispatch(fetchResumeById(resumeId));
};
fetchById();
}, [resumeId, dispatch]);

const handleSave = async () => {
try {
dispatch(setLoading(true));
const input = ref.current;
const canvas = await html2canvas(input);
const imgData = canvas.toDataURL("image/png");
const imgData = await captureScreenshot(ref.current);

if (isCreateMode) {
await dispatch(addResume({ ...selectedResume, imgData })); // Implement addJob logic in your jobSlice
await dispatch(addResume({ ...selectedResume, imgData }));
} else {
await dispatch(updateResume({ ...selectedResume, imgData }));
}
// If the dispatch is successful, navigate to the "/home" route
navigate("/home/resume");
dispatch(setLoading(false));
} catch (error) {
dispatch(setLoading(false));
// If the dispatch fails, handle the error appropriately
console.error("Failed to save resume:", error);
}
};
Expand All @@ -90,7 +95,7 @@ const ResumeBuilder = () => {
dispatch(setTemplate(e.target.value));
};

const handleAIButtonClick = async (e) => {
const handleAIButtonClick = async () => {
await dispatch(improveResumeWithGPT(selectedResume));
};

Expand Down
5 changes: 4 additions & 1 deletion client/src/pages/JobDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const JobOpeningPage = () => {
}
};
let job = useSelector((state) => state.jobs.selectedJob);

const resumesCreatedByUser = useSelector((state) => state.resumeBuilder.resumes);
const dispatch = useDispatch();

Expand Down Expand Up @@ -165,11 +166,13 @@ const JobOpeningPage = () => {
<p>You don't have any resumes, create your first resume for this role!</p>
) : (
<FormControl fullWidth margin="normal">
<InputLabel>Resume</InputLabel>
<Select
labelId="resume-label"
label="Resume"
id="resume"
name="resume"
value={job.resume.id || (resumesCreatedByUser.length > 0 ? resumesCreatedByUser[0]._id : "")}
value={job.resume.id}
onChange={updateSelectedResume}
>
{resumesCreatedByUser.map((resume) => (
Expand Down
1 change: 0 additions & 1 deletion src/constants/auth.js

This file was deleted.

9 changes: 2 additions & 7 deletions src/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import User from "../models/UserModel.js";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { hoursIn10Years } from "../constants/auth.js";

/**
* @desc POST login for a user
Expand All @@ -18,9 +17,7 @@ export const login = async (req, res) => {
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, {
expiresIn: hoursIn10Years,
});
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
return res.status(200).send({
id: user.id,
email,
Expand All @@ -36,8 +33,6 @@ export const register = async (req, res) => {
const { email, password, fullName } = req.body;
const encryptedPassword = await bcrypt.hash(password, salt);
const { id } = await User.create({ email, password: encryptedPassword, fullName });
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: hoursIn10Years,
});
const token = jwt.sign({ id }, process.env.JWT_SECRET);
res.status(201).json({ id, email, token });
};

0 comments on commit 79e8b49

Please sign in to comment.