Skip to content

Commit

Permalink
Merge pull request #6 from aashutoshPanda/integrate-auth-flow
Browse files Browse the repository at this point in the history
Add guest login and integrate auth
  • Loading branch information
aashutoshPanda authored Jan 23, 2024
2 parents e91c49b + de77340 commit f617519
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 48 deletions.
32 changes: 17 additions & 15 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
// src/App.js
import React from "react";
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import { BrowserRouter as Router, Routes, Route, Navigate, Outlet } from "react-router-dom";
import Home from "./pages/Home";
import JobDetail from "./pages/JobDetail";
import BuildResume from "./pages/BuildResume";
import Landing from "./pages/Landing";
import { Typography, Box } from "@mui/material";
import logo from "./assets/logo.png";
import Header from "./components/Header";
import { Provider } from "react-redux";
import store from "./store";
import { localStorageKeyAPIToken } from "./constants/api";

const PrivateRoutes = () => {
const token = localStorage.getItem(localStorageKeyAPIToken); // Replace "yourTokenKey" with the actual key used to store the token
return token ? <Outlet /> : <Navigate to="/" />;
};

function App() {
return (
<Provider store={store}>
<Router>
<Box mt={4} mb={4} textAlign="center" display="flex" alignItems="center" justifyContent="center">
{/* Logo and Title */}
<img src={logo} alt="Logo" style={{ width: "55px", marginRight: "10px", marginBottom: "10px" }} />
<Typography variant="h5">TAILOR MY RESUME</Typography>
</Box>
<Header />
<Routes>
{/* Redirect from / and /home to /home/resume */}
<Route path="/" element={<Navigate to="/resume/new" replace />} />
{/* <Route path="/" element={<Navigate to="/home/resume" replace />} /> */}
<Route path="/home" element={<Navigate to="/home/resume" replace />} />

<Route path="/home/:tab" element={<Home />} />
<Route path="/resume/:id" element={<BuildResume />} />
<Route path="/job/:id" element={<JobDetail />} />
<Route path="/" element={<Landing />} />
<Route element={<PrivateRoutes />}>
<Route path="/home" element={<Navigate to="/home/resume" replace />} />
<Route path="/home/:tab" element={<Home />} />
<Route path="/resume/:id" element={<BuildResume />} />
<Route path="/job/:id" element={<JobDetail />} />
<Route path="*" element={<Navigate to="/home" />} replace />
</Route>
</Routes>
</Router>
</Provider>
Expand Down
7 changes: 3 additions & 4 deletions client/src/api/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// api.js
import axios from "axios";
import { baseURL } from "../constants/api";
import { localStorageKeyAPIToken } from "../constants/api";

const instance = axios.create({ baseURL });

// Add an interceptor for authorization headers
instance.interceptors.request.use((config) => {
// using this token for dev only
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY1YWJiOWViYTNhOTY0Mzk2Y2FmODk1YyIsImlhdCI6MTcwNTg3MDM5NSwiZXhwIjoxNzA1OTU2Nzk1fQ.kn1XpSoTa9R-btlvmzIfM0CHNOhugdl0RDZjCn3S9Xo";

// Retrieve token from local storage
const token = localStorage.getItem(localStorageKeyAPIToken);
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
Expand Down
38 changes: 38 additions & 0 deletions client/src/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// src/components/ResumeCard.js
import React from "react";
import { Typography, Box, Button, Grid, Container } from "@mui/material";
import logo from "../assets/logo.png";
import { useNavigate } from "react-router-dom";
import { localStorageKeyAPIToken } from "../constants/api";

const Header = () => {
const navigate = useNavigate();

const handleLogout = () => {
localStorage.removeItem(localStorageKeyAPIToken);
navigate("/");
};

return (
<Container maxWidth="lg">
<Grid container alignItems="center">
{/* Logo and Title */}
<Grid item xs={6}>
<Box display="flex" alignItems="center">
<img src={logo} alt="Logo" style={{ width: "55px", marginRight: "10px", marginBottom: "10px" }} />
<Typography variant="h5">TAILOR MY RESUME</Typography>
</Box>
</Grid>

{/* Logout Button */}
<Grid item xs={6} container justifyContent="flex-end">
<Button variant="outlined" color="primary" onClick={handleLogout}>
Logout
</Button>
</Grid>
</Grid>
</Container>
);
};

export default Header;
4 changes: 3 additions & 1 deletion client/src/components/JobTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
Typography,
TableSortLabel,
TablePagination,
useTheme,
} from "@mui/material";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
Expand All @@ -28,6 +29,7 @@ const JobOpeningTable = ({ jobOpeningList }) => {
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(8);

const theme = useTheme();
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
Expand Down Expand Up @@ -69,7 +71,7 @@ const JobOpeningTable = ({ jobOpeningList }) => {
};
return (
<div>
<TableContainer component={Paper}>
<TableContainer component={Paper} style={{ marginTop: theme.spacing(2) }}>
<Table>
<TableHead>
<TableRow>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/ResumeCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const ResumeCard = ({ resume }) => {
};

return (
<Card style={{ marginTop: theme.spacing(2) }}>
<Card style={{ marginTop: theme.spacing(2), maxWidth: theme.spacing(80) }}>
{/* Card Content */}
<CardContent>
<Typography variant="h6" component="div" align="left">
Expand Down
1 change: 1 addition & 0 deletions client/src/constants/api.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const baseURL = "http://localhost:3030"; // Replace with your actual API endpoint
export const localStorageKeyAPIToken = "tailor-my-resume-key";
4 changes: 2 additions & 2 deletions client/src/pages/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const HomeScreen = () => {
};

return (
<Container maxWidth="md">
<Box mt={4} mb={4} textAlign="center">
<Container maxWidth="lg">
<Box mb={4} textAlign="center">
{/* Tab Layout */}
<Paper square>
<Tabs value={tabValue} onChange={handleChange} centered>
Expand Down
4 changes: 2 additions & 2 deletions client/src/pages/JobDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ const JobOpeningPage = () => {
if (!job._id && !isCreateMode) return "No such job found";

return (
<Container maxWidth="md">
<Box mt={4}>
<Container maxWidth="lg">
<Box>
{/* ... (previous form fields) */}
<TextField
fullWidth
Expand Down
209 changes: 192 additions & 17 deletions client/src/pages/Landing.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,207 @@
// src/components/LandingPage.js
import React from "react";
import { Container, Typography, Button, Box } from "@mui/material";
import React, { useState, useEffect } from "react";
import { Container, Typography, Button, Box, TextField, Divider, Grid, Tab, Tabs } from "@mui/material";
import jobHunt from "../assets/job-hunt.svg";
import api from "../api";
import { localStorageKeyAPIToken } from "../constants/api";
import { useNavigate } from "react-router-dom";

const LandingPage = () => {
const [value, setValue] = useState(0); // Tab index state
const [email, setUsername] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [passwordError, setPasswordError] = useState("");
const [loginError, setLoginError] = useState("");
const [registrationError, setRegistrationError] = useState("");
const navigate = useNavigate();

useEffect(() => {
const token = localStorage.getItem(localStorageKeyAPIToken);
if (token) {
navigate("/home");
}
}, []);

const handleGuestLogin = () => {
try {
const token = process.env.REACT_APP_GUEST_LOGIN_TOKEN;
localStorage.setItem(localStorageKeyAPIToken, token);
navigate("/home");
} catch (error) {
console.error("Login failed", error);
}
};

const handleRegularLogin = async () => {
try {
const response = await api.post("/auth/login", {
email,
password,
});
const token = response.data.token;
localStorage.setItem(localStorageKeyAPIToken, token);
navigate("/home");
} catch (error) {
console.error("Login failed", error);
setLoginError("Invalid email or password. Please try again.");
}
};

const handleRegister = async () => {
try {
if (password !== confirmPassword) {
setPasswordError("Passwords do not match");
return; // Stop the registration process if passwords do not match
}
setPasswordError("");
const response = await api.post("/auth/register", {
email,
password,
});
const token = response.data.token;
localStorage.setItem(localStorageKeyAPIToken, token);
navigate("/home");
} catch (error) {
console.error("Registration failed", error);
setRegistrationError("Registration failed. Please try again.");
}
};

const handleChange = (event, newValue) => {
setValue(newValue);
};

return (
<Container maxWidth="md">
{/* Slogan */}
<Container maxWidth="lg">
<Typography variant="h6" align="center" paragraph>
Get hired by top product based companies like
Get hired by top product-based companies like
<br />
Google, Microsoft,
<br />
and more.
</Typography>
<Grid container spacing={2}>
{/* First Column - Portrait Image */}
<Grid item xs={12} md={6}>
<Box mt={4} mb={4} textAlign="center">
<img src={jobHunt} alt="Portrait" style={{ height: "450px" }} />
</Box>
</Grid>

{/* Second Column - Buttons */}
<Grid item xs={12} md={6}>
{/* Tabs for Login and Register */}
{/* Guest Login Button */}
<Box mt={2} textAlign="center">
<Button variant="contained" color="secondary" onClick={handleGuestLogin}>
Guest Login
</Button>
</Box>

{/* "OR" Divider */}
<Box mt={2} textAlign="center">
<Divider>OR</Divider>
</Box>
<Tabs value={value} onChange={handleChange} centered>
<Tab label="Login" />
<Tab label="Register" />
</Tabs>

{/* Login Tab Content */}
{value === 0 && (
<>
<Box textAlign="center">
<TextField
label="email"
variant="standard"
margin="normal"
value={email}
onChange={(e) => setUsername(e.target.value)}
/>
</Box>

<Box textAlign="center">
<TextField
label="Password"
type="password"
variant="standard"
margin="normal"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</Box>

<Box textAlign="center">
<Button variant="contained" color="primary" onClick={handleRegularLogin}>
Log In
</Button>
{/* Display login error */}
{loginError && (
<Box textAlign="center" mt={2}>
<Typography variant="body2" color="error">
{loginError}
</Typography>
</Box>
)}
</Box>
</>
)}

{/* Register Tab Content */}
{value === 1 && (
<>
<Box textAlign="center">
<TextField
label="email"
variant="standard"
margin="normal"
value={email}
onChange={(e) => setUsername(e.target.value)}
/>
</Box>

<Box textAlign="center">
<TextField
label="Password"
type="password"
variant="standard"
margin="normal"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</Box>

<Box textAlign="center">
<TextField
label="Confirm Password"
type="password"
variant="standard"
margin="normal"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
error={passwordError !== ""}
helperText={passwordError}
/>
</Box>

{/* Portrait Image */}
{/* Portrait Image */}
<Box mt={4} mb={4} textAlign="center">
<img src={jobHunt} alt="Portrait" style={{ height: "450px" }} />
</Box>

{/* Log In Button */}
<Box mt={4} textAlign="center">
<Button variant="contained" color="primary">
Log In
</Button>
</Box>
<Box textAlign="center">
<Button variant="contained" color="primary" onClick={handleRegister}>
Register
</Button>
{/* Display registration error */}
{registrationError && (
<Box textAlign="center" mt={2}>
<Typography variant="body2" color="error">
{registrationError}
</Typography>
</Box>
)}
</Box>
</>
)}
</Grid>
</Grid>
</Container>
);
};
Expand Down
1 change: 0 additions & 1 deletion client/src/utils/openai.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import OpenAI from "openai";

console.log({ apiKey: process.env.REACT_APP_OPENAI_API_KEY });
const openai = new OpenAI({ apiKey: process.env.REACT_APP_OPENAI_API_KEY, dangerouslyAllowBrowser: true });

const improveWithGPT = async (text) => {
Expand Down
Loading

0 comments on commit f617519

Please sign in to comment.