From 2887f05ae4ddb5cd91b222f3cc0f2fd9a219f757 Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 22 Apr 2025 09:02:58 +0300 Subject: [PATCH 01/16] added initial app design --- nextstep-frontend/src/App.tsx | 2 + nextstep-frontend/src/components/TopBar.tsx | 2 +- nextstep-frontend/src/pages/MainDashboard.tsx | 185 ++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 nextstep-frontend/src/pages/MainDashboard.tsx diff --git a/nextstep-frontend/src/App.tsx b/nextstep-frontend/src/App.tsx index 58f988e..81e7611 100644 --- a/nextstep-frontend/src/App.tsx +++ b/nextstep-frontend/src/App.tsx @@ -13,6 +13,7 @@ import Chat from './pages/Chat'; import Resume from './pages/Resume'; import TopBar from './components/TopBar'; import Layout from './components/Layout'; +import MainDashboard from './pages/MainDashboard'; const App: React.FC = () => { return ( @@ -28,6 +29,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> } /> diff --git a/nextstep-frontend/src/components/TopBar.tsx b/nextstep-frontend/src/components/TopBar.tsx index 2a3350d..a2177e3 100644 --- a/nextstep-frontend/src/components/TopBar.tsx +++ b/nextstep-frontend/src/components/TopBar.tsx @@ -23,7 +23,7 @@ const TopBar: React.FC = () => { - navigate('/dashboard')} sx={{ mx: 1 }}> + navigate('/main-dashboard')} sx={{ mx: 1 }}> diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx new file mode 100644 index 0000000..b5db55a --- /dev/null +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -0,0 +1,185 @@ +import React, { useState, useEffect } from 'react'; +import { Container, Box, Typography, Button, TextField, Chip, Stack, Grid, Paper, Autocomplete, MenuItem, Select, FormControl, InputLabel } from '@mui/material'; +import { GitHub, LinkedIn } from '@mui/icons-material'; + +const roles = [ + 'Software Engineer', + 'Software Developer', + 'Frontend Developer', + 'Backend Developer', + 'Full Stack Developer', + 'DevOps Engineer', + 'Data Scientist', + 'Machine Learning Engineer', + 'Product Manager', + 'UI/UX Designer', +]; + +const skillsList = [ + 'Leadership', + 'React', + 'JavaScript', + 'TypeScript', + 'Python', + 'Java', + 'C++', + 'Node.js', + 'Express', + 'MongoDB', + 'SQL', + 'AWS', + 'Docker', + 'Kubernetes', + 'Git', + 'Agile Methodologies', + 'Problem Solving', + 'Communication', +]; + +const MainDashboard: React.FC = () => { + const [aboutMe, setAboutMe] = useState(() => localStorage.getItem('aboutMe') || ''); + const [skills, setSkills] = useState(() => JSON.parse(localStorage.getItem('skills') || '[]')); + const [newSkill, setNewSkill] = useState(''); + const [selectedRole, setSelectedRole] = useState(() => localStorage.getItem('selectedRole') || ''); + + useEffect(() => { + localStorage.setItem('aboutMe', aboutMe); + }, [aboutMe]); + + useEffect(() => { + localStorage.setItem('skills', JSON.stringify(skills)); + }, [skills]); + + useEffect(() => { + localStorage.setItem('selectedRole', selectedRole); + }, [selectedRole]); + + const handleAddSkill = (skill: string) => { + if (skill.trim() && !skills.includes(skill.trim())) { + setSkills([...skills, skill.trim()]); + } + }; + + const handleDeleteSkill = (skillToDelete: string) => { + setSkills(skills.filter(skill => skill !== skillToDelete)); + }; + + return ( + + + {/* Main Content */} + + + + About Me + + setAboutMe(e.target.value)} + sx={{ mb: 3 }} + /> + + Desired Role + + setSelectedRole(value)} + onChange={(e, value) => setSelectedRole(value || '')} + renderInput={(params) => ( + + )} + /> + + Skills + + + {skills.map((skill, index) => ( + handleDeleteSkill(skill)} + color="primary" + sx={{ mb: 1 }} + /> + ))} + + setNewSkill(value)} + onChange={(e, value) => handleAddSkill(value || '')} + renderInput={(params) => ( + setNewSkill(e.target.value)} + /> + )} + sx={{ mb: 2 }} + /> + + + + + {/* Sidebar */} + + + + Connect Accounts + + + + + + + + ); +}; + +export default MainDashboard; From cbf0f34e77edcab3b8e04121eb4d4d89fa76ecb4 Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 22 Apr 2025 21:33:35 +0300 Subject: [PATCH 02/16] added github connection with skills update --- nextstep-backend/src/app.ts | 2 + .../src/controllers/github_controller.ts | 87 +++++++++++++++++++ nextstep-backend/src/routes/github_routes.ts | 10 +++ nextstep-frontend/src/handlers/githubAuth.ts | 72 +++++++++++++++ nextstep-frontend/src/pages/MainDashboard.tsx | 49 +++++++++++ 5 files changed, 220 insertions(+) create mode 100644 nextstep-backend/src/controllers/github_controller.ts create mode 100644 nextstep-backend/src/routes/github_routes.ts create mode 100644 nextstep-frontend/src/handlers/githubAuth.ts diff --git a/nextstep-backend/src/app.ts b/nextstep-backend/src/app.ts index 371440b..fb7f02a 100644 --- a/nextstep-backend/src/app.ts +++ b/nextstep-backend/src/app.ts @@ -15,6 +15,7 @@ import validateUser from "./middleware/validateUser"; import loadOpenApiFile from "./openapi/openapi_loader"; import resource_routes from './routes/resources_routes'; import resume_routes from './routes/resume_routes'; +import githubRoutes from './routes/github_routes'; const specs = swaggerJsdoc(options); @@ -74,5 +75,6 @@ app.use('/user', usersRoutes); app.use('/resource', resource_routes); app.use('/room', roomsRoutes); app.use('/resume', resume_routes); +app.use('/github', githubRoutes); export { app, corsOptions }; diff --git a/nextstep-backend/src/controllers/github_controller.ts b/nextstep-backend/src/controllers/github_controller.ts new file mode 100644 index 0000000..56f1368 --- /dev/null +++ b/nextstep-backend/src/controllers/github_controller.ts @@ -0,0 +1,87 @@ +import axios from 'axios'; +import { Request, Response } from 'express'; + +const clientId = process.env.GITHUB_CLIENT_ID; +const clientSecret = process.env.GITHUB_CLIENT_SECRET; + +export const handleGitHubOAuth = async (req: Request, res: Response) => { + const { code } = req.body; + + if (!code) { + return res.status(400).json({ error: 'Authorization code is required' }); + } + + try { + const tokenResponse = await axios.post('https://github.com/login/oauth/access_token', { + headers: { 'Content-Type': 'application/json' }, + client_id: clientId, + client_secret: clientSecret, + code: code, + }) as any; + + const tokenData = await tokenResponse.data; + const params = new URLSearchParams(tokenData); + const accessToken = params.get('access_token'); + + if (!accessToken) { + return res.status(400).json({ error: 'Failed to retrieve access token' }); + } + + const userResponse = await axios.get('https://api.github.com/user', { + headers: { Authorization: `Bearer ${accessToken}` }, + }) as {status: number, data: { login?: string }, json: () => Promise}; + + if (userResponse.status !== 200) { + const errorText = await userResponse.data; + return res.status(400).json({ error: errorText }); + } + + const userData = await userResponse.data; + res.json({ username: userData.login }); + } catch (error) { + console.error('Error during GitHub OAuth:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}; + +export const fetchGitHubRepos = async (req: Request, res: Response) => { + const { username } = req.params; + + try { + const apiUrl = `https://api.github.com/users/${username}/repos`; + const response = await axios.get(apiUrl) as {data: any, status: number}; + + if (response.status !== 200) { + return res.status(400).json({ error: `Error fetching repos: ${response.status}` }); + } + + const repos = await response.data; + res.json(repos); + } catch (error) { + console.error('Error fetching repos:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}; + +export const fetchRepoLanguages = async (req: Request, res: Response) => { + const { repoUrl } = req.query; + + if (!repoUrl) { + return res.status(400).json({ error: 'Repository URL is required' }); + } + + try { + // Convert the repoUrl to the GitHub API URL if necessary + const apiUrl = (repoUrl as string).replace('https://github.com/', 'https://api.github.com/repos/'); + const response = await axios.get(`${apiUrl}/languages`); + + if (response.status !== 200) { + return res.status(400).json({ error: `Error fetching languages: ${response.statusText}` }); + } + + res.json(response.data); + } catch (error) { + console.error('Error fetching languages:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}; diff --git a/nextstep-backend/src/routes/github_routes.ts b/nextstep-backend/src/routes/github_routes.ts new file mode 100644 index 0000000..5969109 --- /dev/null +++ b/nextstep-backend/src/routes/github_routes.ts @@ -0,0 +1,10 @@ +import express from 'express'; +import { handleGitHubOAuth, fetchGitHubRepos, fetchRepoLanguages } from '../controllers/github_controller'; + +const router = express.Router(); + +router.post('/oauth', handleGitHubOAuth); +router.get('/repos/:username', fetchGitHubRepos); +router.get('/languages', fetchRepoLanguages); + +export default router; diff --git a/nextstep-frontend/src/handlers/githubAuth.ts b/nextstep-frontend/src/handlers/githubAuth.ts new file mode 100644 index 0000000..92a5d4f --- /dev/null +++ b/nextstep-frontend/src/handlers/githubAuth.ts @@ -0,0 +1,72 @@ +import api from "../serverApi.ts"; + +// Function to fetch GitHub repositories by username +export const fetchGitHubRepos = async (username: string) => { + try { + const response = await api.get(`github/repos/${username}`) as any; + if (response.status !== 200) { + throw new Error(`Error fetching repos: ${response.statusText}`); + } + return response.data; + } catch (error) { + console.error(error); + return []; + } +}; + +// Function to connect to GitHub by username +export const connectToGitHub = async (username: string) => { + if (!username) { + throw new Error('Username is required to connect to GitHub.'); + } + return await fetchGitHubRepos(username); +}; + +// Function to initiate GitHub OAuth login (redirect only) +export const initiateGitHubOAuth = () => { + const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID; // Use environment variable + const redirectUri = import.meta.env.VITE_GITHUB_REDIRECT_URI; // Use environment variable + const scope = 'repo'; // Adjust scope as needed + const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`; + window.location.href = authUrl; // Redirect the user to GitHub's authorization page +}; + +// Function to handle GitHub OAuth token exchange and fetching user details +export const handleGitHubOAuth = async (code: string) => { + try { + const response = await api.post('github/oauth', { + headers: { 'Content-Type': 'application/json' }, + code: code, + }) as {data: {username?: string, error?: string}, status: number}; + + if (response.status !== 200) { + const errorText = await response.data.error; + console.error('Backend OAuth Error:', errorText); + throw new Error('Failed to authenticate with GitHub'); + } + else if (!response.data.username) { + console.error('Backend OAuth Error:', response.data.error); + throw new Error('Failed to retrieve user information from GitHub'); + } + + return response.data.username; + } catch (error) { + const err : Error = error as Error; + console.error('Error during GitHub OAuth:', error); + throw new Error('Internal server error: ' + err.message); + } +}; + +// Function to fetch languages for a specific repository +export const fetchRepoLanguages = async (repoUrl: string) => { + try { + const response = await api.get(`github/languages?repoUrl=${encodeURIComponent(repoUrl)}`) as any; + if (response.status !== 200) { + throw new Error(`Error fetching languages: ${response.statusText}`); + } + return await response.data; + } catch (error) { + console.error(error); + return {}; + } +}; \ No newline at end of file diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index b5db55a..92568fd 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Container, Box, Typography, Button, TextField, Chip, Stack, Grid, Paper, Autocomplete, MenuItem, Select, FormControl, InputLabel } from '@mui/material'; import { GitHub, LinkedIn } from '@mui/icons-material'; +import { connectToGitHub, initiateGitHubOAuth, fetchRepoLanguages, handleGitHubOAuth } from '../handlers/githubAuth'; const roles = [ 'Software Engineer', @@ -41,6 +42,7 @@ const MainDashboard: React.FC = () => { const [skills, setSkills] = useState(() => JSON.parse(localStorage.getItem('skills') || '[]')); const [newSkill, setNewSkill] = useState(''); const [selectedRole, setSelectedRole] = useState(() => localStorage.getItem('selectedRole') || ''); + const [repos, setRepos] = useState<{ id: number; name: string; html_url: string }[]>([]); useEffect(() => { localStorage.setItem('aboutMe', aboutMe); @@ -64,6 +66,40 @@ const MainDashboard: React.FC = () => { setSkills(skills.filter(skill => skill !== skillToDelete)); }; + const handleGitHubConnect = async () => { + try { + initiateGitHubOAuth(); + } catch (error) { + console.error('Error initiating GitHub OAuth:', error); + } + }; + + useEffect(() => { + const queryParams = new URLSearchParams(window.location.search); + const code = queryParams.get('code'); + if (code) { + const fetchGitHubData = async () => { + try { + const username = await handleGitHubOAuth(code); + const fetchedRepos = await connectToGitHub(username); + setRepos(fetchedRepos); + + // Fetch languages and add them as skills + const languagesSet = new Set(skills); + for (const repo of fetchedRepos) { + const repoLanguages = await fetchRepoLanguages(repo.html_url); + Object.keys(repoLanguages).forEach((lang) => languagesSet.add(lang)); + } + setSkills(Array.from(languagesSet)); + } catch (error) { + console.error('Error fetching GitHub data:', error); + } + }; + + fetchGitHubData(); + } + }, []); + return ( { color="secondary" startIcon={} fullWidth + onClick={handleGitHubConnect} > Connect to GitHub + + GitHub Repositories + + From 9fa24e47122162e5559b80164d6f88fae47ce40e Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 22 Apr 2025 21:37:49 +0300 Subject: [PATCH 03/16] added small change --- nextstep-frontend/src/pages/MainDashboard.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 92568fd..81e79fb 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -212,9 +212,11 @@ const MainDashboard: React.FC = () => { > Connect to GitHub - + { + repos.length > 0 && GitHub Repositories + }
    {repos.map((repo) => (
  • @@ -223,8 +225,8 @@ const MainDashboard: React.FC = () => {
  • ))} -
- + +
From f591da561be2c06a775d6c092593eca51f159bf1 Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 22 Apr 2025 21:39:27 +0300 Subject: [PATCH 04/16] fix --- nextstep-frontend/src/pages/MainDashboard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 81e79fb..abf544a 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -225,8 +225,8 @@ const MainDashboard: React.FC = () => { ))} - - + + From ca01f01849ee7bf4a0bee859475cc50ca3c2e927 Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 22 Apr 2025 21:54:15 +0300 Subject: [PATCH 05/16] added small design change --- nextstep-frontend/src/pages/MainDashboard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index abf544a..547e44d 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -217,10 +217,10 @@ const MainDashboard: React.FC = () => { GitHub Repositories } -
    +
      {repos.map((repo) => ( -
    • - +
    • + {repo.name}
    • From 7e17c641becbb38cc395f86c28654dd225e12663 Mon Sep 17 00:00:00 2001 From: lina elman Date: Thu, 24 Apr 2025 11:07:38 +0300 Subject: [PATCH 06/16] changed to read only from github --- nextstep-frontend/src/handlers/githubAuth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextstep-frontend/src/handlers/githubAuth.ts b/nextstep-frontend/src/handlers/githubAuth.ts index 92a5d4f..4c6fae3 100644 --- a/nextstep-frontend/src/handlers/githubAuth.ts +++ b/nextstep-frontend/src/handlers/githubAuth.ts @@ -26,7 +26,7 @@ export const connectToGitHub = async (username: string) => { export const initiateGitHubOAuth = () => { const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID; // Use environment variable const redirectUri = import.meta.env.VITE_GITHUB_REDIRECT_URI; // Use environment variable - const scope = 'repo'; // Adjust scope as needed + const scope = 'read:repo'; // Only read access to repositories const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`; window.location.href = authUrl; // Redirect the user to GitHub's authorization page }; From 50d82b9f76f2fff5bbf3fd6abd39376c523992fd Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 26 Apr 2025 18:08:05 +0300 Subject: [PATCH 07/16] added choose between github oauth or without --- .../src/controllers/github_controller.ts | 8 +++- nextstep-frontend/src/handlers/githubAuth.ts | 4 +- nextstep-frontend/src/pages/MainDashboard.tsx | 47 +++++++++++++++++-- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/nextstep-backend/src/controllers/github_controller.ts b/nextstep-backend/src/controllers/github_controller.ts index 56f1368..1df6563 100644 --- a/nextstep-backend/src/controllers/github_controller.ts +++ b/nextstep-backend/src/controllers/github_controller.ts @@ -46,10 +46,16 @@ export const handleGitHubOAuth = async (req: Request, res: Response) => { export const fetchGitHubRepos = async (req: Request, res: Response) => { const { username } = req.params; + const { accessToken } = req.query; // Optional access token for authenticated requests try { const apiUrl = `https://api.github.com/users/${username}/repos`; - const response = await axios.get(apiUrl) as {data: any, status: number}; + + const headers = accessToken + ? { Authorization: `Bearer ${accessToken}` } + : undefined; + + const response = await axios.get(apiUrl, { headers }) as { data: any, status: number }; if (response.status !== 200) { return res.status(400).json({ error: `Error fetching repos: ${response.status}` }); diff --git a/nextstep-frontend/src/handlers/githubAuth.ts b/nextstep-frontend/src/handlers/githubAuth.ts index 4c6fae3..5961d59 100644 --- a/nextstep-frontend/src/handlers/githubAuth.ts +++ b/nextstep-frontend/src/handlers/githubAuth.ts @@ -18,7 +18,7 @@ export const fetchGitHubRepos = async (username: string) => { export const connectToGitHub = async (username: string) => { if (!username) { throw new Error('Username is required to connect to GitHub.'); - } + } return await fetchGitHubRepos(username); }; @@ -26,7 +26,7 @@ export const connectToGitHub = async (username: string) => { export const initiateGitHubOAuth = () => { const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID; // Use environment variable const redirectUri = import.meta.env.VITE_GITHUB_REDIRECT_URI; // Use environment variable - const scope = 'read:repo'; // Only read access to repositories + const scope = 'public_repo'; // Only read access to repositories const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`; window.location.href = authUrl; // Redirect the user to GitHub's authorization page }; diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 547e44d..7cfa23d 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -43,6 +43,8 @@ const MainDashboard: React.FC = () => { const [newSkill, setNewSkill] = useState(''); const [selectedRole, setSelectedRole] = useState(() => localStorage.getItem('selectedRole') || ''); const [repos, setRepos] = useState<{ id: number; name: string; html_url: string }[]>([]); + const [useOAuth, setUseOAuth] = useState(true); // Toggle for GitHub connection method + const [showAuthOptions, setShowAuthOptions] = useState(false); // Toggle for showing auth options useEffect(() => { localStorage.setItem('aboutMe', aboutMe); @@ -67,10 +69,35 @@ const MainDashboard: React.FC = () => { }; const handleGitHubConnect = async () => { + if (!showAuthOptions) { + setShowAuthOptions(true); // Show auth options first + return; + } + try { - initiateGitHubOAuth(); + if (useOAuth) { + initiateGitHubOAuth(); + } else { + const username = prompt('Enter GitHub username:'); + if (!username) { + alert('GitHub username is required for No Auth connection.'); + return; + } + const fetchedRepos = await connectToGitHub(username); + setRepos(fetchedRepos); + + // Fetch languages and add them as skills + const languagesSet = new Set(skills); + for (const repo of fetchedRepos) { + const repoLanguages = await fetchRepoLanguages(repo.html_url); + Object.keys(repoLanguages).forEach((lang) => languagesSet.add(lang)); + } + setSkills(Array.from(languagesSet)); + } } catch (error) { - console.error('Error initiating GitHub OAuth:', error); + console.error('Error connecting to GitHub:', error); + } finally { + setShowAuthOptions(false); // Close auth options after proceeding } }; @@ -203,6 +230,18 @@ const MainDashboard: React.FC = () => { > Connect to LinkedIn + {showAuthOptions && ( + + GitHub Connection Method + + + )} { repos.length > 0 && @@ -226,7 +265,7 @@ const MainDashboard: React.FC = () => { ))}
    - + From acb7f56a0e7f9fd1683540bb26f72e5b5f5abf02 Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 26 Apr 2025 18:43:58 +0300 Subject: [PATCH 08/16] little fixes --- nextstep-frontend/src/pages/MainDashboard.tsx | 302 ++++++++++-------- 1 file changed, 171 insertions(+), 131 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 7cfa23d..37b45a4 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -1,40 +1,27 @@ import React, { useState, useEffect } from 'react'; -import { Container, Box, Typography, Button, TextField, Chip, Stack, Grid, Paper, Autocomplete, MenuItem, Select, FormControl, InputLabel } from '@mui/material'; +import { + Container, Box, Typography, TextField, Chip, Stack, + Grid, Paper, Autocomplete, MenuItem, Select, FormControl, + InputLabel, Divider, Avatar, Button +} from '@mui/material'; import { GitHub, LinkedIn } from '@mui/icons-material'; -import { connectToGitHub, initiateGitHubOAuth, fetchRepoLanguages, handleGitHubOAuth } from '../handlers/githubAuth'; +import { + connectToGitHub, + initiateGitHubOAuth, + fetchRepoLanguages, + handleGitHubOAuth +} from '../handlers/githubAuth'; const roles = [ - 'Software Engineer', - 'Software Developer', - 'Frontend Developer', - 'Backend Developer', - 'Full Stack Developer', - 'DevOps Engineer', - 'Data Scientist', - 'Machine Learning Engineer', - 'Product Manager', - 'UI/UX Designer', + 'Software Engineer', 'Software Developer', 'Frontend Developer', + 'Backend Developer', 'Full Stack Developer', 'DevOps Engineer', + 'Data Scientist', 'Machine Learning Engineer', 'Product Manager', 'UI/UX Designer' ]; const skillsList = [ - 'Leadership', - 'React', - 'JavaScript', - 'TypeScript', - 'Python', - 'Java', - 'C++', - 'Node.js', - 'Express', - 'MongoDB', - 'SQL', - 'AWS', - 'Docker', - 'Kubernetes', - 'Git', - 'Agile Methodologies', - 'Problem Solving', - 'Communication', + 'Leadership', 'React', 'JavaScript', 'TypeScript', 'Python', 'Java', + 'C++', 'Node.js', 'Express', 'MongoDB', 'SQL', 'AWS', 'Docker', + 'Kubernetes', 'Git', 'Agile Methodologies', 'Problem Solving', 'Communication' ]; const MainDashboard: React.FC = () => { @@ -43,24 +30,17 @@ const MainDashboard: React.FC = () => { const [newSkill, setNewSkill] = useState(''); const [selectedRole, setSelectedRole] = useState(() => localStorage.getItem('selectedRole') || ''); const [repos, setRepos] = useState<{ id: number; name: string; html_url: string }[]>([]); - const [useOAuth, setUseOAuth] = useState(true); // Toggle for GitHub connection method - const [showAuthOptions, setShowAuthOptions] = useState(false); // Toggle for showing auth options + const [useOAuth, setUseOAuth] = useState(true); + const [showAuthOptions, setShowAuthOptions] = useState(false); - useEffect(() => { - localStorage.setItem('aboutMe', aboutMe); - }, [aboutMe]); - - useEffect(() => { - localStorage.setItem('skills', JSON.stringify(skills)); - }, [skills]); - - useEffect(() => { - localStorage.setItem('selectedRole', selectedRole); - }, [selectedRole]); + useEffect(() => { localStorage.setItem('aboutMe', aboutMe); }, [aboutMe]); + useEffect(() => { localStorage.setItem('skills', JSON.stringify(skills)); }, [skills]); + useEffect(() => { localStorage.setItem('selectedRole', selectedRole); }, [selectedRole]); const handleAddSkill = (skill: string) => { if (skill.trim() && !skills.includes(skill.trim())) { setSkills([...skills, skill.trim()]); + setNewSkill(''); } }; @@ -69,60 +49,51 @@ const MainDashboard: React.FC = () => { }; const handleGitHubConnect = async () => { - if (!showAuthOptions) { - setShowAuthOptions(true); // Show auth options first - return; - } - + if (!showAuthOptions) { setShowAuthOptions(true); return; } try { if (useOAuth) { initiateGitHubOAuth(); } else { const username = prompt('Enter GitHub username:'); - if (!username) { - alert('GitHub username is required for No Auth connection.'); - return; - } + if (!username) { alert('GitHub username is required.'); return; } const fetchedRepos = await connectToGitHub(username); setRepos(fetchedRepos); - - // Fetch languages and add them as skills const languagesSet = new Set(skills); for (const repo of fetchedRepos) { const repoLanguages = await fetchRepoLanguages(repo.html_url); - Object.keys(repoLanguages).forEach((lang) => languagesSet.add(lang)); + Object.keys(repoLanguages).forEach(lang => languagesSet.add(lang)); } setSkills(Array.from(languagesSet)); } } catch (error) { console.error('Error connecting to GitHub:', error); } finally { - setShowAuthOptions(false); // Close auth options after proceeding + setShowAuthOptions(false); } }; + const handleBackToGitHubOptions = () => { + setShowAuthOptions(false); // Reset the GitHub connection options + }; + useEffect(() => { - const queryParams = new URLSearchParams(window.location.search); - const code = queryParams.get('code'); + const code = new URLSearchParams(window.location.search).get('code'); if (code) { const fetchGitHubData = async () => { try { const username = await handleGitHubOAuth(code); const fetchedRepos = await connectToGitHub(username); setRepos(fetchedRepos); - - // Fetch languages and add them as skills const languagesSet = new Set(skills); for (const repo of fetchedRepos) { const repoLanguages = await fetchRepoLanguages(repo.html_url); - Object.keys(repoLanguages).forEach((lang) => languagesSet.add(lang)); + Object.keys(repoLanguages).forEach(lang => languagesSet.add(lang)); } setSkills(Array.from(languagesSet)); } catch (error) { console.error('Error fetching GitHub data:', error); } }; - fetchGitHubData(); } }, []); @@ -131,39 +102,59 @@ const MainDashboard: React.FC = () => { - - {/* Main Content */} + + {/* Left Side (Main Content) */} - - + + About Me setAboutMe(e.target.value)} sx={{ mb: 3 }} /> - - Desired Role - + + Desired Role { /> )} /> - - Skills - - + + Skills + {skills.map((skill, index) => ( handleDeleteSkill(skill)} - color="primary" + color="secondary" + variant="outlined" sx={{ mb: 1 }} /> ))} @@ -209,62 +209,102 @@ const MainDashboard: React.FC = () => { )} sx={{ mb: 2 }} /> - - {/* Sidebar */} - - - - Connect Accounts - - - {showAuthOptions && ( - - GitHub Connection Method - setUseOAuth(e.target.value === 'oauth')} + > + OAuth + No Auth + + + + + + ) : ( + <> + + + + )} + {repos.length > 0 && ( + + GitHub Repositories + + {repos.map(repo => ( + + + {repo.name} + + + ))} + + )} - - { - repos.length > 0 && - GitHub Repositories - - } - From 6c0b8a8875e571247e04cbe33adb728b48c0eb14 Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 26 Apr 2025 18:55:12 +0300 Subject: [PATCH 09/16] fix overflow --- nextstep-frontend/src/pages/MainDashboard.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 37b45a4..9640d5a 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -102,11 +102,11 @@ const MainDashboard: React.FC = () => { { sx={{ flex: 1, height: '100%', // Ensure the grid fills the container height - overflow: 'hidden', // Prevent grid-level scrolling + overflowY: 'hidden', // Prevent grid-level scrolling }} > {/* Left Side (Main Content) */} @@ -138,6 +138,7 @@ const MainDashboard: React.FC = () => { flex: 1, display: 'flex', flexDirection: 'column', + height: '100%', // Ensure it fills the parent height }} > @@ -151,7 +152,7 @@ const MainDashboard: React.FC = () => { placeholder="Write about yourself..." value={aboutMe} onChange={(e) => setAboutMe(e.target.value)} - sx={{ mb: 3 }} + sx={{ mb: 3, }} /> Desired Role From 5878753262d4c5579b7db8453404460dee15e271 Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 26 Apr 2025 19:01:54 +0300 Subject: [PATCH 10/16] fix --- nextstep-frontend/src/pages/MainDashboard.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 9640d5a..9c38e13 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -104,6 +104,7 @@ const MainDashboard: React.FC = () => { sx={{ height: 'calc(100vh - 64px)', // Adjust height to account for headers/footers display: 'flex', + mt: '-20px', flexDirection: 'column', overflowY: 'hidden', // Prevent scrolling on the entire page maxHeight: '100%', // Ensure the container does not exceed viewport height From 7bdc9f704ba92aaded7bf8a4c88c73cb2b22a6a3 Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 3 May 2025 15:49:07 +0300 Subject: [PATCH 11/16] added design changes --- nextstep-frontend/src/pages/MainDashboard.tsx | 193 ++++++------------ 1 file changed, 58 insertions(+), 135 deletions(-) diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index 9c38e13..b9f3dbb 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -32,6 +32,7 @@ const MainDashboard: React.FC = () => { const [repos, setRepos] = useState<{ id: number; name: string; html_url: string }[]>([]); const [useOAuth, setUseOAuth] = useState(true); const [showAuthOptions, setShowAuthOptions] = useState(false); + const [showAllSkills, setShowAllSkills] = useState(false); useEffect(() => { localStorage.setItem('aboutMe', aboutMe); }, [aboutMe]); useEffect(() => { localStorage.setItem('skills', JSON.stringify(skills)); }, [skills]); @@ -73,7 +74,7 @@ const MainDashboard: React.FC = () => { }; const handleBackToGitHubOptions = () => { - setShowAuthOptions(false); // Reset the GitHub connection options + setShowAuthOptions(false); }; useEffect(() => { @@ -99,52 +100,19 @@ const MainDashboard: React.FC = () => { }, []); return ( - - - {/* Left Side (Main Content) */} - - - - About Me - + + + {/* Left Side */} + + + About Me { placeholder="Write about yourself..." value={aboutMe} onChange={(e) => setAboutMe(e.target.value)} - sx={{ mb: 3, }} + sx={{ mb: 3 }} /> Desired Role @@ -164,12 +132,7 @@ const MainDashboard: React.FC = () => { onInputChange={(e, value) => setSelectedRole(value)} onChange={(e, value) => setSelectedRole(value || '')} renderInput={(params) => ( - + )} /> @@ -180,8 +143,8 @@ const MainDashboard: React.FC = () => { sx={{ flexWrap: 'wrap', mb: 2, - maxHeight: '150px', - overflowY: 'auto', // Allow scrolling for skills if they overflow + minHeight: showAllSkills ? '22vh' : '9vh', + overflowY: showAllSkills ? 'auto' : 'hidden', }} > {skills.map((skill, index) => ( @@ -195,44 +158,43 @@ const MainDashboard: React.FC = () => { /> ))} - setNewSkill(value)} - onChange={(e, value) => handleAddSkill(value || '')} - renderInput={(params) => ( - setNewSkill(e.target.value)} - /> - )} - sx={{ mb: 2 }} - /> + + + setNewSkill(value)} + onChange={(e, value) => value && handleAddSkill(value)} + renderInput={(params) => ( + { + if (e.key === 'Enter') { + e.preventDefault(); + handleAddSkill(newSkill); + } + }} + /> + )} + /> + + - {/* Right Side (Sidebar) */} - - + {/* Right Side */} + + Connect Accounts {showAuthOptions ? ( @@ -247,45 +209,13 @@ const MainDashboard: React.FC = () => { No Auth - - + + ) : ( <> - - + + )} {repos.length > 0 && ( @@ -294,14 +224,7 @@ const MainDashboard: React.FC = () => { {repos.map(repo => ( - - {repo.name} - + {repo.name} ))} From 7cf082e63405fc782a167c86d527debae51f4ed5 Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 3 May 2025 16:03:41 +0300 Subject: [PATCH 12/16] reverted unnecessary changes --- nextstep-frontend/src/App.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nextstep-frontend/src/App.tsx b/nextstep-frontend/src/App.tsx index 81e7611..e6277ce 100644 --- a/nextstep-frontend/src/App.tsx +++ b/nextstep-frontend/src/App.tsx @@ -20,15 +20,15 @@ const App: React.FC = () => { <> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> From 80a9a49a2940d0a34c6a5b28ea989961d6da1bde Mon Sep 17 00:00:00 2001 From: lina elman Date: Sat, 3 May 2025 16:15:46 +0300 Subject: [PATCH 13/16] added small fix --- nextstep-frontend/src/App.tsx | 2 +- nextstep-frontend/src/pages/MainDashboard.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nextstep-frontend/src/App.tsx b/nextstep-frontend/src/App.tsx index e6277ce..75e65d3 100644 --- a/nextstep-frontend/src/App.tsx +++ b/nextstep-frontend/src/App.tsx @@ -20,7 +20,7 @@ const App: React.FC = () => { <> - } /> + } /> } /> } /> } /> diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index b9f3dbb..f1185a5 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -129,8 +129,8 @@ const MainDashboard: React.FC = () => { freeSolo options={roles} value={selectedRole} - onInputChange={(e, value) => setSelectedRole(value)} - onChange={(e, value) => setSelectedRole(value || '')} + onInputChange={(_e, value) => setSelectedRole(value)} + onChange={(_e, value) => setSelectedRole(value || '')} renderInput={(params) => ( )} @@ -171,8 +171,8 @@ const MainDashboard: React.FC = () => { fullWidth options={skillsList} value={newSkill} - onInputChange={(e, value) => setNewSkill(value)} - onChange={(e, value) => value && handleAddSkill(value)} + onInputChange={(_e, value) => setNewSkill(value)} + onChange={(_e, value) => value && handleAddSkill(value)} renderInput={(params) => ( Date: Tue, 6 May 2025 21:41:39 +0300 Subject: [PATCH 14/16] added ui changes --- .../src/models/github_connection_model.ts | 33 ++ nextstep-backend/src/models/resume_model.ts | 33 ++ nextstep-frontend/src/pages/Login.tsx | 4 +- nextstep-frontend/src/pages/MainDashboard.tsx | 382 ++++++++++-------- 4 files changed, 284 insertions(+), 168 deletions(-) create mode 100644 nextstep-backend/src/models/github_connection_model.ts create mode 100644 nextstep-backend/src/models/resume_model.ts diff --git a/nextstep-backend/src/models/github_connection_model.ts b/nextstep-backend/src/models/github_connection_model.ts new file mode 100644 index 0000000..9f3d8f8 --- /dev/null +++ b/nextstep-backend/src/models/github_connection_model.ts @@ -0,0 +1,33 @@ +import mongoose, { Schema, Document } from 'mongoose'; + +export interface IGitHubConnection extends Document { + userId: mongoose.Schema.Types.ObjectId; + githubUsername: string; + repositories: { + name: string; + url: string; + languages: string[]; + }[]; +} + +const githubConnectionSchema: Schema = new Schema({ + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: true, + unique: true, + }, + githubUsername: { + type: String, + required: true, + }, + repositories: [ + { + name: { type: String, required: true }, + url: { type: String, required: true }, + languages: { type: [String], default: [] }, + }, + ], +}, { timestamps: true, versionKey: false }); + +export const GitHubConnectionModel = mongoose.model('GitHubConnection', githubConnectionSchema); diff --git a/nextstep-backend/src/models/resume_model.ts b/nextstep-backend/src/models/resume_model.ts new file mode 100644 index 0000000..2d47c56 --- /dev/null +++ b/nextstep-backend/src/models/resume_model.ts @@ -0,0 +1,33 @@ +import mongoose, { Schema, Document } from 'mongoose'; + +export interface IResume extends Document { + userId: mongoose.Schema.Types.ObjectId; + filename: string; + uploadedAt: Date; + score?: number; + feedback?: string; +} + +const resumeSchema: Schema = new Schema({ + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: true, + }, + filename: { + type: String, + required: true, + }, + uploadedAt: { + type: Date, + default: Date.now, + }, + score: { + type: Number, + }, + feedback: { + type: String, + }, +}, { timestamps: true, versionKey: false }); + +export const ResumeModel = mongoose.model('Resume', resumeSchema); diff --git a/nextstep-frontend/src/pages/Login.tsx b/nextstep-frontend/src/pages/Login.tsx index fec6550..741691f 100644 --- a/nextstep-frontend/src/pages/Login.tsx +++ b/nextstep-frontend/src/pages/Login.tsx @@ -32,7 +32,7 @@ const Login: React.FC = () => { setUserAuth(res.data); - navigate("/dashboard"); + navigate("/main-dashboard"); } catch (error) { console.error("Google login failed:", error); setError("Google login failed."); @@ -51,7 +51,7 @@ const Login: React.FC = () => { // Handle successful login, e.g., save tokens, redirect, etc. setUserAuth(response.data) - navigate('/dashboard'); // Redirect to dashboard or another page after login + navigate('/main-dashboard'); // Redirect to dashboard or another page after login } catch (error) { // Handle login error diff --git a/nextstep-frontend/src/pages/MainDashboard.tsx b/nextstep-frontend/src/pages/MainDashboard.tsx index f1185a5..1d25426 100644 --- a/nextstep-frontend/src/pages/MainDashboard.tsx +++ b/nextstep-frontend/src/pages/MainDashboard.tsx @@ -1,10 +1,28 @@ import React, { useState, useEffect } from 'react'; import { - Container, Box, Typography, TextField, Chip, Stack, - Grid, Paper, Autocomplete, MenuItem, Select, FormControl, - InputLabel, Divider, Avatar, Button + Container, + Grid, + Box, + Typography, + TextField, + Button, + Chip, + Stack, + Avatar, + Divider, + Autocomplete, + FormControl, + InputLabel, + Select, + MenuItem } from '@mui/material'; -import { GitHub, LinkedIn } from '@mui/icons-material'; +import { + GitHub, + LinkedIn, + Person as PersonIcon, + Work as WorkIcon, + Build as BuildIcon +} from '@mui/icons-material'; import { connectToGitHub, initiateGitHubOAuth, @@ -13,15 +31,13 @@ import { } from '../handlers/githubAuth'; const roles = [ - 'Software Engineer', 'Software Developer', 'Frontend Developer', - 'Backend Developer', 'Full Stack Developer', 'DevOps Engineer', - 'Data Scientist', 'Machine Learning Engineer', 'Product Manager', 'UI/UX Designer' + 'Software Engineer', 'Frontend Developer', 'Backend Developer', + 'Full Stack Developer', 'DevOps Engineer', 'Product Manager', 'UI/UX Designer' ]; const skillsList = [ - 'Leadership', 'React', 'JavaScript', 'TypeScript', 'Python', 'Java', - 'C++', 'Node.js', 'Express', 'MongoDB', 'SQL', 'AWS', 'Docker', - 'Kubernetes', 'Git', 'Agile Methodologies', 'Problem Solving', 'Communication' + 'React', 'JavaScript', 'TypeScript', 'Python', 'Java', 'Node.js', + 'Express', 'MongoDB', 'AWS', 'Docker', 'Kubernetes', 'Git', 'Agile' ]; const MainDashboard: React.FC = () => { @@ -32,205 +48,239 @@ const MainDashboard: React.FC = () => { const [repos, setRepos] = useState<{ id: number; name: string; html_url: string }[]>([]); const [useOAuth, setUseOAuth] = useState(true); const [showAuthOptions, setShowAuthOptions] = useState(false); + + // NEW: control how many skills to show before toggling const [showAllSkills, setShowAllSkills] = useState(false); + const SKILL_DISPLAY_LIMIT = 6; + const shouldShowToggle = skills.length > SKILL_DISPLAY_LIMIT; useEffect(() => { localStorage.setItem('aboutMe', aboutMe); }, [aboutMe]); useEffect(() => { localStorage.setItem('skills', JSON.stringify(skills)); }, [skills]); useEffect(() => { localStorage.setItem('selectedRole', selectedRole); }, [selectedRole]); - const handleAddSkill = (skill: string) => { - if (skill.trim() && !skills.includes(skill.trim())) { - setSkills([...skills, skill.trim()]); - setNewSkill(''); + useEffect(() => { + const code = new URLSearchParams(window.location.search).get('code'); + if (code) { + (async () => { + try { + const username = await handleGitHubOAuth(code); + const fetched = await connectToGitHub(username); + setRepos(fetched); + mergeRepoLanguages(fetched); + } catch (e) { + console.error(e); + } + })(); + } + }, []); + + const mergeRepoLanguages = async (fetchedRepos: typeof repos) => { + const langSet = new Set(skills); + for (const repo of fetchedRepos) { + const langs = await fetchRepoLanguages(repo.html_url); + Object.keys(langs).forEach(lang => langSet.add(lang)); } + setSkills(Array.from(langSet)); + }; + + const handleAddSkill = (skill: string) => { + const trimmed = skill.trim(); + if (!trimmed || skills.includes(trimmed)) return; + setSkills(prev => [trimmed, ...prev]); + setNewSkill(''); }; const handleDeleteSkill = (skillToDelete: string) => { - setSkills(skills.filter(skill => skill !== skillToDelete)); + setSkills(prev => prev.filter(s => s !== skillToDelete)); }; const handleGitHubConnect = async () => { - if (!showAuthOptions) { setShowAuthOptions(true); return; } + if (!showAuthOptions) return setShowAuthOptions(true); try { - if (useOAuth) { - initiateGitHubOAuth(); - } else { + if (useOAuth) initiateGitHubOAuth(); + else { const username = prompt('Enter GitHub username:'); - if (!username) { alert('GitHub username is required.'); return; } - const fetchedRepos = await connectToGitHub(username); - setRepos(fetchedRepos); - const languagesSet = new Set(skills); - for (const repo of fetchedRepos) { - const repoLanguages = await fetchRepoLanguages(repo.html_url); - Object.keys(repoLanguages).forEach(lang => languagesSet.add(lang)); - } - setSkills(Array.from(languagesSet)); + if (!username) return alert('Username required'); + const fetched = await connectToGitHub(username); + setRepos(fetched); + mergeRepoLanguages(fetched); } - } catch (error) { - console.error('Error connecting to GitHub:', error); + } catch (e) { + console.error(e); } finally { setShowAuthOptions(false); } }; - const handleBackToGitHubOptions = () => { - setShowAuthOptions(false); - }; - - useEffect(() => { - const code = new URLSearchParams(window.location.search).get('code'); - if (code) { - const fetchGitHubData = async () => { - try { - const username = await handleGitHubOAuth(code); - const fetchedRepos = await connectToGitHub(username); - setRepos(fetchedRepos); - const languagesSet = new Set(skills); - for (const repo of fetchedRepos) { - const repoLanguages = await fetchRepoLanguages(repo.html_url); - Object.keys(repoLanguages).forEach(lang => languagesSet.add(lang)); - } - setSkills(Array.from(languagesSet)); - } catch (error) { - console.error('Error fetching GitHub data:', error); - } - }; - fetchGitHubData(); - } - }, []); - return ( - + {/* Left Side */} - - About Me - setAboutMe(e.target.value)} - sx={{ mb: 3 }} - /> - - Desired Role - setSelectedRole(value)} - onChange={(_e, value) => setSelectedRole(value || '')} - renderInput={(params) => ( - - )} - /> - - Skills - - {skills.map((skill, index) => ( - handleDeleteSkill(skill)} - color="secondary" - variant="outlined" - sx={{ mb: 1 }} - /> - ))} - - - + + {/* About Me Section */} + + + + + About Me + + + setAboutMe(e.target.value)} + /> + + + {/* Desired Role Section */} + + + + + Desired Role + + setNewSkill(value)} - onChange={(_e, value) => value && handleAddSkill(value)} - renderInput={(params) => ( - { - if (e.key === 'Enter') { - e.preventDefault(); - handleAddSkill(newSkill); - } - }} - /> + options={roles} + value={selectedRole} + onInputChange={(_, val) => setSelectedRole(val)} + renderInput={params => ( + )} /> - - - + + + {/* Skills Section */} + + + + + Skills + + + + + {/* Show only up to the limit when collapsed */} + + {(showAllSkills ? skills : skills.slice(0, SKILL_DISPLAY_LIMIT)).map(skill => ( + handleDeleteSkill(skill)} + /> + ))} + + + {/* Render toggle button only if there are extra skills */} + {shouldShowToggle && ( + + )} + + {/* Add New Skill */} + + setNewSkill(val)} + onChange={(_, val) => val && handleAddSkill(val)} + renderInput={params => ( + e.key === 'Enter' && handleAddSkill(newSkill)} + /> + )} + sx={{ flexGrow: 1 }} + /> + + + + {/* Right Side */} - - - Connect Accounts + + + + Connect Accounts + + {showAuthOptions ? ( - <> + - GitHub Connection Method - + Method - - - + + + + ) : ( - <> - - - + + + + )} + {repos.length > 0 && ( - - GitHub Repositories - + + + Repositories: + + {repos.map(repo => ( - - {repo.name} - + ))} - + )} - + From 0110f1e0f257fa6acf8fcd8d61e00bb0917b420d Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 6 May 2025 21:43:17 +0300 Subject: [PATCH 15/16] removed unnecessary --- .../src/models/github_connection_model.ts | 33 ------------------- nextstep-backend/src/models/resume_model.ts | 33 ------------------- 2 files changed, 66 deletions(-) delete mode 100644 nextstep-backend/src/models/github_connection_model.ts delete mode 100644 nextstep-backend/src/models/resume_model.ts diff --git a/nextstep-backend/src/models/github_connection_model.ts b/nextstep-backend/src/models/github_connection_model.ts deleted file mode 100644 index 9f3d8f8..0000000 --- a/nextstep-backend/src/models/github_connection_model.ts +++ /dev/null @@ -1,33 +0,0 @@ -import mongoose, { Schema, Document } from 'mongoose'; - -export interface IGitHubConnection extends Document { - userId: mongoose.Schema.Types.ObjectId; - githubUsername: string; - repositories: { - name: string; - url: string; - languages: string[]; - }[]; -} - -const githubConnectionSchema: Schema = new Schema({ - userId: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: true, - unique: true, - }, - githubUsername: { - type: String, - required: true, - }, - repositories: [ - { - name: { type: String, required: true }, - url: { type: String, required: true }, - languages: { type: [String], default: [] }, - }, - ], -}, { timestamps: true, versionKey: false }); - -export const GitHubConnectionModel = mongoose.model('GitHubConnection', githubConnectionSchema); diff --git a/nextstep-backend/src/models/resume_model.ts b/nextstep-backend/src/models/resume_model.ts deleted file mode 100644 index 2d47c56..0000000 --- a/nextstep-backend/src/models/resume_model.ts +++ /dev/null @@ -1,33 +0,0 @@ -import mongoose, { Schema, Document } from 'mongoose'; - -export interface IResume extends Document { - userId: mongoose.Schema.Types.ObjectId; - filename: string; - uploadedAt: Date; - score?: number; - feedback?: string; -} - -const resumeSchema: Schema = new Schema({ - userId: { - type: mongoose.Schema.Types.ObjectId, - ref: 'User', - required: true, - }, - filename: { - type: String, - required: true, - }, - uploadedAt: { - type: Date, - default: Date.now, - }, - score: { - type: Number, - }, - feedback: { - type: String, - }, -}, { timestamps: true, versionKey: false }); - -export const ResumeModel = mongoose.model('Resume', resumeSchema); From 5de1e1da1f88a995b5d6bd6e7ae90d646f4eb114 Mon Sep 17 00:00:00 2001 From: lina elman Date: Tue, 6 May 2025 21:55:15 +0300 Subject: [PATCH 16/16] changed footer & top bar colors --- nextstep-frontend/src/components/Footer.css | 2 +- nextstep-frontend/src/components/TopBar.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nextstep-frontend/src/components/Footer.css b/nextstep-frontend/src/components/Footer.css index 404eb5f..16fe36d 100644 --- a/nextstep-frontend/src/components/Footer.css +++ b/nextstep-frontend/src/components/Footer.css @@ -1,5 +1,5 @@ .footer { - background-color: var(--color-5); + background-color: #233752; color: var(--color-2); padding: 10px 20px; text-align: center; diff --git a/nextstep-frontend/src/components/TopBar.tsx b/nextstep-frontend/src/components/TopBar.tsx index a2177e3..a23a6fe 100644 --- a/nextstep-frontend/src/components/TopBar.tsx +++ b/nextstep-frontend/src/components/TopBar.tsx @@ -20,7 +20,7 @@ const TopBar: React.FC = () => { }; return ( - + navigate('/main-dashboard')} sx={{ mx: 1 }}>