diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..8d8629e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": true, + "jsxSingleQuote": true, + "singleQuote": true +} \ No newline at end of file diff --git a/README.md b/README.md index 9b02843..e7b123f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ A platform where developers from across the globe meets employers and vice versa # 📖 MeetDevs -**MeetDevs** is a cutting-edge website designed to connect employers with talented individuals in the tech industry. With a user-friendly interface and advanced search features, MeetDevs makes it easy for employers to find the perfect candidates for their projects or job openings. Employers can browse through a diverse pool of skilled professionals, filtering by specific skills, experience level, and location. The platform also allows employers to view detailed profiles, portfolios, and resumes of potential hires, making the selection process more efficient and informed. MeetDevs aims to streamline the hiring process, bringing together employers and talented developers in a seamless and productive manner. +**MeetDevs** is a cutting-edge website designed to connect employers with talented individuals in the tech industry. With a user-friendly interface and advanced search features, MeetDevs makes it easy for employers to find the perfect candidates for their projects or job openings. Employers can browse through a diverse pool of skilled professionals, filtering by specific skills, experience level, and location. The platform also allows employers to view detailed profiles, portfolios, and resumes of potential hires, making the selection process more efficient and informed. MeetDevs aims to streamline the hiring process, bringing together employers and talented developers in a seamless and productive manner. You don't have to be a networking pro! to get that your dream job, you just need be a master at your craft and you will get that your dream job you deserve. So, even as an introvert you can get that job ## 🛠Built With ### MERN Stack @@ -63,10 +63,8 @@ A platform where developers from across the globe meets employers and vice versa ### Key Features -- **Ranking System**: -- **Fairness Policy**: - -
+- **Ranking System**: Talent get ranked based on their skills, years of experience and collaborations, leveraging github api to obtain metrics to be used to calculate talent rank percentile and weekly coding challenge, thus employer can easily identify the top 1% on the platform +- **Fairness Policy**: Every talent has a fair chance of getting their dream job, for no talent can accept two offers at a time, hence, other talent has a fair chance of getting served eventually. diff --git a/client/index.html b/client/index.html index 00f7415..66edfdd 100644 --- a/client/index.html +++ b/client/index.html @@ -1,9 +1,9 @@ - + =8" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1662,6 +1669,12 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1694,6 +1707,21 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js." + }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1708,6 +1736,16 @@ "node": ">= 8" } }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1725,6 +1763,26 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/daisyui": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.9.3.tgz", + "integrity": "sha512-8li177QCu6dqlEOzE3h/dAV1y9Movbjx5bzJIO/hNqMNZtJkbHM0trjTzbDejV7N57eNGdjBvAGtxZYKzS4jow==", + "dev": true, + "dependencies": { + "colord": "^2.9", + "css-selector-tokenizer": "^0.8", + "postcss": "^8", + "postcss-js": "^4", + "tailwindcss": "^3.1" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -1813,6 +1871,14 @@ "integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==", "dev": true }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", @@ -2173,6 +2239,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2182,6 +2254,20 @@ "reusify": "^1.0.4" } }, + "node_modules/fbjs": { + "version": "0.8.18", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz", + "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==", + "dependencies": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.30" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2422,6 +2508,17 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2544,12 +2641,29 @@ "node": ">=8" } }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "node_modules/jiti": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", @@ -2795,6 +2909,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", @@ -3158,6 +3281,14 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -3252,6 +3383,32 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, + "node_modules/react-file-base64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/react-file-base64/-/react-file-base64-1.0.3.tgz", + "integrity": "sha512-itGMFH6IkJUZF2p0YXQnUBqzUHFaMYcs+ssD9e4j1XJGHRibGe8kiLr6y46oAIw1JknX/bJUUogDJOk/o91TMg==", + "dependencies": { + "react": "^15.6.1" + }, + "peerDependencies": { + "react": "^15.0.2" + } + }, + "node_modules/react-file-base64/node_modules/react": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-15.7.0.tgz", + "integrity": "sha512-5/MMRYmpmM0sMTHGLossnJCrmXQIiJilD6y3YN3TzAwGFj6zdnMtFv6xmi65PHKRV+pehIHpT7oy67Sr6s9AHA==", + "dependencies": { + "create-react-class": "^15.6.0", + "fbjs": "^0.8.9", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0", + "prop-types": "^15.5.10" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-icons": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz", @@ -3506,6 +3663,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -3547,6 +3709,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3816,6 +3983,28 @@ "node": ">=14.17" } }, + "node_modules/ua-parser-js": { + "version": "0.7.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.36.tgz", + "integrity": "sha512-CPPLoCts2p7D8VbybttE3P2ylv0OBZEAy7a12DsulIEcAiMtWJy+PBgMXgWDI80D5UwqE8oQPHYnk13tm38M2Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -3932,6 +4121,11 @@ "loose-envify": "^1.0.0" } }, + "node_modules/whatwg-fetch": { + "version": "3.6.19", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", + "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/client/package.json b/client/package.json index 20032b9..eaefbb0 100644 --- a/client/package.json +++ b/client/package.json @@ -17,6 +17,7 @@ "react": "^18.2.0", "react-datepicker": "^4.20.0", "react-dom": "^18.2.0", + "react-file-base64": "^1.0.3", "react-icons": "^4.11.0", "react-redux": "^8.1.3", "react-router-dom": "^6.16.0", @@ -31,6 +32,7 @@ "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-react": "^4.0.3", "autoprefixer": "^10.4.16", + "daisyui": "^3.9.3", "eslint": "^8.45.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.3", diff --git a/client/src/actions/education.ts b/client/src/actions/education.ts index 736dbea..8443ab6 100644 --- a/client/src/actions/education.ts +++ b/client/src/actions/education.ts @@ -13,6 +13,7 @@ export const getEducationsTalent = try { setLoading(true); const { data } = await getTalentEducations(talentId); + dispatch({ type: 'FETCH_TALENT_EDUCATION', payload: data }); setLoading(false); } catch (error: any) { diff --git a/client/src/actions/talent.ts b/client/src/actions/talent.ts index 66706fb..fc2f9ba 100644 --- a/client/src/actions/talent.ts +++ b/client/src/actions/talent.ts @@ -1,5 +1,7 @@ import { getAllTalents, getATalent, patchTalent } from '../api/talent'; +import { talentsPerPage } from '../api/pagination'; + export const getTalents = (setLoading) => async (dispatch) => { try { setLoading(true); @@ -11,6 +13,17 @@ export const getTalents = (setLoading) => async (dispatch) => { } }; +export const getTalentsPerPage = (setLoading, pageNo) => async (dispatch) => { + try { + setLoading(true); + const { data } = await talentsPerPage(pageNo); + dispatch({ type: 'FETCH_ALL_PAGINATE', payload: data }); + setLoading(false); + } catch (error) { + console.log(error.message); + } +}; + export const getTalent = (setLoading, id) => async (dispatch) => { try { setLoading(true); diff --git a/client/src/api/pagination.ts b/client/src/api/pagination.ts new file mode 100644 index 0000000..706d271 --- /dev/null +++ b/client/src/api/pagination.ts @@ -0,0 +1,6 @@ +import axios from 'axios'; + +export const talentsPerPage = (pageNo) => { + const talents = axios.get(`http://localhost:3000/api/talents?page=${pageNo}`); + return talents; +}; diff --git a/client/src/api/project.ts b/client/src/api/project.ts index dd9e234..d743177 100644 --- a/client/src/api/project.ts +++ b/client/src/api/project.ts @@ -1,22 +1,22 @@ import axios from 'axios'; export const getTalentProjects = (talentId) => { - const talentProjects = axios.get( - `http://localhost:3000/projects/talent/${talentId}` - ); - return talentProjects; + const talentProjects = axios.get( + `http://localhost:3000/projects/talent/${talentId}`, + ); + return talentProjects; }; export const updateProject = (id, project) => { - const res = axios.put(`http://localhost:3000/projects/${id}`, project); - return res; + const res = axios.put(`http://localhost:3000/projects/${id}`, project); + return res; }; export const deleteProject = (id) => { - axios.delete(`http://localhost:3000/projects/${id}`); + axios.delete(`http://localhost:3000/projects/${id}`); }; export const createProject = (projectData) => { - const data = axios.post('http://localhost:3000/projects', projectData); - return data; + const data = axios.post('http://localhost:3000/projects', projectData); + return data; }; diff --git a/client/src/components/DropDown/DropDown.css b/client/src/components/DropDown/DropDown.css new file mode 100644 index 0000000..dd3d1b6 --- /dev/null +++ b/client/src/components/DropDown/DropDown.css @@ -0,0 +1,36 @@ +.dropDownProfile{ + position: absolute; + top: 5rem; + right: 2rem; + width: 120px; + padding: 15px; + border-radius: 15px; + background-color: rgb(62, 143, 62); + border: 1px solid gray; + color: black; +} + +.dropDownProfile::before{ + content: ''; + position: absolute; + top: -0.7rem; + left: 65px; + /* right: 1.1px; */ + width: 24px; + height: 24px; + transform: rotate(37deg); + background-color: white; + border-left: 1px solid gray; + border-top: 1px solid gray; + background-color: rgb(62, 143, 62); + +} + +.logout{ + cursor: pointer; + font-weight: 600; + box-sizing: content-box; + border-radius: 8px; + padding-left: 16px; + background-color: rgb(189, 45, 45); +} \ No newline at end of file diff --git a/client/src/components/DropDown/DropDown.tsx b/client/src/components/DropDown/DropDown.tsx new file mode 100644 index 0000000..96101df --- /dev/null +++ b/client/src/components/DropDown/DropDown.tsx @@ -0,0 +1,16 @@ +import './DropDown.css' + +function ProfileDropDownMenu({ logout }: { logout: () => void }): JSX.Element { + + return ( +