├── test
└── .gitkeep
├── src
├── App.css
├── setupTests.js
├── App.test.js
├── components
│ ├── LoadComp.css
│ ├── ChatBody.css
│ ├── NoChats.js
│ ├── OrgEndCard.css
│ ├── SkillCard.css
│ ├── LineChart.js
│ ├── Search.css
│ ├── GenererateQR.js
│ ├── EmployeeCard.css
│ ├── OrgEndCard.js
│ ├── CodeforcesGraph.js
│ ├── Modals.css
│ ├── SearchEmp.js
│ ├── LoadComp.js
│ ├── ScanQR.js
│ ├── SearchBar.js
│ ├── GetSkillsModals.js
│ ├── SkillCard.js
│ ├── GetEmployeeModal.js
│ ├── GetEditFieldModal.js
│ ├── GetCertificationModal.js
│ ├── GetEducationModal.js
│ ├── GetWorkExpModal.js
│ ├── ChatBody.js
│ └── Navbar.js
├── reportWebVitals.js
├── contracts
│ ├── Migrations.sol
│ ├── OrganizationEndorser.sol
│ ├── Skills.sol
│ ├── Admin.sol
│ └── Employee.sol
├── index.css
├── firebase
│ ├── firebase.js
│ └── api.js
├── index.js
├── pages
│ ├── NoRole
│ │ ├── Notifications.css
│ │ ├── NoRole.css
│ │ ├── Notifications.js
│ │ └── NoRole.js
│ ├── GetRoutes
│ │ ├── GetOrg.css
│ │ ├── Employee.css
│ │ └── GetOrg.js
│ ├── Employee
│ │ ├── Employee.css
│ │ ├── UpdateProfile.css
│ │ └── Notifications.js
│ ├── Admin
│ │ ├── AllEmployees.js
│ │ ├── AllOrganizationEndorser.js
│ │ ├── Admin.css
│ │ ├── Notifications.js
│ │ └── CreateUser.js
│ └── OrganizationEndorser
│ │ ├── EndorsePage.css
│ │ ├── Organization.css
│ │ ├── Organization.js
│ │ ├── Notifications.js
│ │ ├── EndorseSkill.js
│ │ └── EndorseSection.js
├── MetaMaskGuide.js
├── logo.svg
└── App.js
├── .babelrc
├── public
├── robots.txt
├── favicon.ico
├── logo192.png
├── logo512.png
├── manifest.json
└── index.html
├── migrations
├── 1_initial_migration.js
└── 2_deploy_contracts.js
├── .vscode
└── settings.json
├── .gitignore
├── web.config
├── truffle-config.js
├── package.json
├── .github
└── workflows
│ ├── azure-static-web-apps-ashy-ocean-068119800.yml
│ ├── azure-static-web-apps-kind-grass-06d9d2100.yml
│ ├── azure-static-web-apps-nice-cliff-0fcb7af00.yml
│ └── azure-static-web-apps-agreeable-pebble-0716f3500.yml
└── README.md
/test/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2", "stage-3"]
3 | }
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itsaaryan/skillset-verified/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itsaaryan/skillset-verified/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itsaaryan/skillset-verified/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | const Migrations = artifacts.require("Migrations");
2 |
3 | module.exports = function (deployer) {
4 | deployer.deploy(Migrations);
5 | };
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "appService.defaultWebAppToDeploy": "/subscriptions/03d5f8ae-756b-4b02-8cfc-47a30de7bfc8/resourceGroups/appsvc_linux_centralus/providers/Microsoft.Web/sites/skillset-verified",
3 | "appService.deploySubpath": "build"
4 | }
5 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render( );
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/LoadComp.css:
--------------------------------------------------------------------------------
1 | .load-comp {
2 | position: fixed;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | -webkit-transform: translate(-50%, -50%);
7 | -moz-transform: translate(-50%, -50%);
8 | -o-transform: translate(-50%, -50%);
9 | -ms-transform: translate(-50%, -50%);
10 | margin-top: 30px;
11 | }
12 |
--------------------------------------------------------------------------------
/migrations/2_deploy_contracts.js:
--------------------------------------------------------------------------------
1 | const Admin = artifacts.require("Admin");
2 | const Skills = artifacts.require("Skills");
3 |
4 | module.exports = async function (deployer, network, accounts) {
5 | await deployer.deploy(Admin);
6 | const admin = await Admin.deployed();
7 | await deployer.deploy(Skills);
8 | const skills = await Skills.deployed();
9 | console.log(admin.address, skills.address);
10 | };
11 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | seed-phrase.js
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/src/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.5.0 <0.9.0;
3 |
4 | contract Migrations {
5 | address public owner = msg.sender;
6 | uint256 public last_completed_migration;
7 |
8 | modifier restricted() {
9 | require(
10 | msg.sender == owner,
11 | "This function is restricted to the contract's owner"
12 | );
13 | _;
14 | }
15 |
16 | function setCompleted(uint256 completed) public restricted {
17 | last_completed_migration = completed;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/ChatBody.css:
--------------------------------------------------------------------------------
1 | .design-chat-input > input {
2 | background: rgba(31, 30, 30, 0.581) !important;
3 | border: 1px solid white !important;
4 | box-shadow: inset 0 0 3px #c5c6c7 !important;
5 | color: white !important;
6 | }
7 |
8 | .design-chat-input > button {
9 | background: rgba(31, 30, 30, 0.581) !important;
10 | color: white !important;
11 | border: 1px solid white !important;
12 | box-shadow: inset 0 0 8px #c5c6c7 !important;
13 | }
14 |
15 | .design-chat-input > button:hover {
16 | box-shadow: inset 0 0 15px #c5c6c7 !important;
17 | transform: scale(1.03, 1.03);
18 | }
19 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Grand+Hotel&display=swap");
2 | @import url("https://fonts.googleapis.com/css2?family=Arvo&display=swap");
3 |
4 | body {
5 | margin: 0;
6 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
7 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
8 | sans-serif;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | background: #0b0c10ea !important;
12 | color: #c5c6c7 !important;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
--------------------------------------------------------------------------------
/src/firebase/firebase.js:
--------------------------------------------------------------------------------
1 | import firebase from "firebase/app";
2 | import "firebase/firestore";
3 |
4 | const firebaseConfig = {
5 | apiKey: "AIzaSyA3pOj1Ex5Y95upo3WYO-LtlO9O3-H-usc",
6 | authDomain: "skillset-verified.firebaseapp.com",
7 | projectId: "skillset-verified",
8 | storageBucket: "skillset-verified.appspot.com",
9 | messagingSenderId: "75144383574",
10 | appId: "1:75144383574:web:75af1487584a97169b7ff7",
11 | measurementId: "G-REQXD214NH",
12 | };
13 | if (!firebase.apps.length) {
14 | firebase.initializeApp(firebaseConfig);
15 | firebase.firestore();
16 | }
17 |
18 | export const db = firebase.firestore();
19 |
20 | export default firebase;
21 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import reportWebVitals from "./reportWebVitals";
6 | import "semantic-ui-css/semantic.min.css";
7 | import "react-circular-progressbar/dist/styles.css";
8 |
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById("root")
14 | );
15 |
16 | // If you want to start measuring performance in your app, pass a function
17 | // to log results (for example: reportWebVitals(console.log))
18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19 | reportWebVitals();
20 |
--------------------------------------------------------------------------------
/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/NoChats.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Image } from "semantic-ui-react";
3 |
4 | export default class Nochats extends Component {
5 | render() {
6 | return (
7 |
16 |
20 |
No Chats
21 |
22 | Feel free to discuss any matters the chats are end to end encrypted.
23 |
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/OrgEndCard.css:
--------------------------------------------------------------------------------
1 | .organization-card {
2 | width: 70% !important;
3 | margin-left: auto !important;
4 | margin-right: auto !important;
5 | background: #393b3fa6 !important;
6 | border-radius: 7px !important;
7 | border: 1px solid white !important;
8 | box-shadow: 0px 0px 1px 0px white !important;
9 | color: white !important;
10 | margin-bottom: 2rem !important;
11 | }
12 |
13 | .organization-card:hover {
14 | transform: scale(1.03, 1.03);
15 | }
16 |
17 | .organization-card > .content > .header {
18 | display: flex !important;
19 | justify-content: space-between !important;
20 | flex-wrap: wrap !important;
21 | color: white !important;
22 | }
23 |
24 | .organization-card > .content > .header > small {
25 | font-size: 12px !important;
26 | font-weight: 600 !important;
27 | font-style: italic;
28 | }
29 |
30 | @media only screen and (max-width: 800px) {
31 | .organization-card {
32 | width: 100% !important;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/pages/NoRole/Notifications.css:
--------------------------------------------------------------------------------
1 | .sidechat-container {
2 | margin-top: 2rem;
3 | margin-left: 1rem;
4 | }
5 |
6 | .notifications {
7 | background: rgba(31, 30, 30, 0.581);
8 | width: 85%;
9 | margin-left: auto;
10 | margin-right: auto;
11 | height: 80vh;
12 | margin-top: 40px;
13 | border-radius: 10px;
14 | border: 1px solid white;
15 | box-shadow: inset 0 0 3px 0 white;
16 | }
17 |
18 | .sidechat-body {
19 | overflow: auto !important;
20 | }
21 |
22 | .notification-sidechat {
23 | color: white !important;
24 | }
25 |
26 | .notification-sidechat-subheading {
27 | color: #c5c6c7 !important;
28 | }
29 |
30 | .header-row > th {
31 | border-bottom: 1px solid white !important;
32 | }
33 |
34 | .row-cell-container {
35 | cursor: pointer;
36 | }
37 |
38 | .header-row-cell {
39 | border-bottom: 1px solid #c5c6c7 !important;
40 | }
41 |
42 | .row-cell-container :hover {
43 | transform: scale(1.01, 1.01);
44 | background: rgba(31, 30, 30, 0.1);
45 | }
46 |
--------------------------------------------------------------------------------
/src/components/SkillCard.css:
--------------------------------------------------------------------------------
1 | .delete-button-skill {
2 | position: absolute;
3 | right: 0;
4 | margin-top: 10px;
5 | margin-right: 10px;
6 | height: 30px;
7 | width: 30px;
8 | display: grid;
9 | justify-content: center;
10 | align-items: center;
11 | justify-items: center;
12 | cursor: pointer;
13 | }
14 |
15 | .delete-button-skill:hover {
16 | transform: scale(1.1, 1.1);
17 | }
18 |
19 | .skill-des {
20 | background: #393b3fa6 !important;
21 | border-radius: 7px !important;
22 | border: 1px solid white !important;
23 | color: white !important;
24 | width: 100% !important;
25 | margin-bottom: 12px !important;
26 | }
27 |
28 | .skill-des > .content > div > .header {
29 | display: flex !important;
30 | justify-content: space-between !important;
31 | flex-wrap: wrap !important;
32 | color: white !important;
33 | }
34 |
35 | .skillcard_container {
36 | display: flex;
37 | justify-content: space-between;
38 | }
39 |
40 | .skillcard_container > div:nth-child(2) {
41 | margin-top: 25px;
42 | }
43 |
--------------------------------------------------------------------------------
/src/pages/GetRoutes/GetOrg.css:
--------------------------------------------------------------------------------
1 | .org-card {
2 | width: 70% !important;
3 | margin-left: auto !important;
4 | margin-right: auto !important;
5 | background: #393b3fa6 !important;
6 | border-radius: 7px !important;
7 | border: 1px solid white !important;
8 | box-shadow: 2px 0px 3px 1px white !important;
9 | color: white !important;
10 | }
11 |
12 | .add-employee {
13 | padding: 10px;
14 | float: right;
15 | display: grid;
16 | justify-items: center;
17 | align-items: center;
18 | border: 2px solid rgb(255, 255, 255);
19 | background-color: #393b3fa6;
20 | border-radius: 10px;
21 | box-shadow: inset 0px 0px 10px #c5c6c7;
22 | cursor: pointer;
23 | margin-top: 16px;
24 | color: white;
25 | padding-bottom: 12px;
26 | margin-top: -5px;
27 | }
28 |
29 | .add-employee:hover {
30 | transform: scale(1.1, 1.1);
31 | box-shadow: inset 0px 0px 20px white;
32 | }
33 |
34 | .org-card-heading {
35 | font-family: "Arvo", serif !important;
36 | color: white;
37 | font-size: 25px;
38 | font-weight: 500;
39 | }
40 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
25 | Skillset Verified
26 |
27 |
28 | You need to enable JavaScript to run this app.
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/truffle-config.js:
--------------------------------------------------------------------------------
1 | require("babel-register");
2 | require("babel-polyfill");
3 |
4 | const HDWalletProvider = require("@truffle/hdwallet-provider");
5 | const { SEED_PHRASE, INFURA_KEY } = require("./seed-phrase");
6 | const infuraKey = INFURA_KEY;
7 | const seedPhrase = SEED_PHRASE;
8 |
9 | module.exports = {
10 | networks: {
11 | development: {
12 | host: "127.0.0.1", // Localhost (default: none)
13 | port: 7545, // Standard Ethereum port (default: none)
14 | network_id: "*", // Any network (default: none,
15 | },
16 | rinkeby: {
17 | provider: () => new HDWalletProvider(seedPhrase, infuraKey),
18 | network_id: 4,
19 | gas: 5500000,
20 | confirmations: 2,
21 | timeoutBlocks: 200000000000000,
22 | skipDryRun: true,
23 | },
24 | },
25 | contracts_directory: "./src/contracts/",
26 | contracts_build_directory: "./src/abis/",
27 | compilers: {
28 | solc: {
29 | optimizer: {
30 | enabled: true,
31 | runs: 200,
32 | },
33 | evmVersion: "petersburg",
34 | },
35 | },
36 | plugins: ["truffle-contract-size"],
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/LineChart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Line } from "react-chartjs-2";
3 |
4 | export default class LineChart extends Component {
5 | state = {
6 | data: {},
7 | options: {},
8 | newdata: {},
9 | };
10 |
11 | componentDidMount = () => {
12 | setTimeout(() => {
13 | var data = {
14 | labels: [...Array(this.props.overallEndorsement?.length).keys()],
15 | datasets: [
16 | {
17 | label: "Endorse Rating Spread",
18 | data: this.props.overallEndorsement,
19 | fill: false,
20 | backgroundColor: "white",
21 | borderColor: "rgba(255,255,255,0.3)",
22 | },
23 | ],
24 | };
25 |
26 | var options = {
27 | scales: {
28 | yAxes: [
29 | {
30 | ticks: {
31 | beginAtZero: true,
32 | },
33 | },
34 | ],
35 | },
36 | };
37 | this.setState({
38 | data,
39 | options,
40 | });
41 | }, 1000);
42 | };
43 | render() {
44 | return ;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/MetaMaskGuide.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Segment, Button, Image } from "semantic-ui-react";
3 |
4 | export default class MetaMaskGuide extends Component {
5 | render() {
6 | return (
7 |
19 |
24 |
25 | Oops!.. Seems like you do not have metamask extension.
26 | Please download it to proceed.
27 |
28 | After the metamask set-up , create an account on Rinkeby test
29 | network.
30 |
31 |
32 | Download Metamask Extension
33 |
34 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/contracts/OrganizationEndorser.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0 <0.9.0;
2 |
3 | contract OrganizationEndorser {
4 | address admin;
5 | string name;
6 | address organization_address;
7 | string description;
8 | string location;
9 |
10 | constructor(
11 | address _admin,
12 | address _organization_address,
13 | string memory _name,
14 | string memory _description,
15 | string memory _location
16 | ) public {
17 | admin = _admin;
18 | name = _name;
19 | organization_address = _organization_address;
20 | description = _description;
21 | location = _location;
22 | }
23 |
24 | function getOrganizationInfo()
25 | public
26 | view
27 | returns (
28 | string memory,
29 | address,
30 | string memory,
31 | string memory
32 | )
33 | {
34 | return (name, organization_address, description, location);
35 | }
36 |
37 | address[] allEmployees;
38 |
39 | function addEmployees(address employee_address) public {
40 | require(msg.sender == organization_address);
41 | allEmployees.push(employee_address);
42 | }
43 |
44 | function totalEmployees() public view returns (uint256) {
45 | return allEmployees.length;
46 | }
47 |
48 | function getEmployeeByIndex(uint256 index) public view returns (address) {
49 | return allEmployees[index];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/contracts/Skills.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0 <0.9.0;
2 |
3 | contract Skills {
4 | mapping(string => address[]) skillmap;
5 | string[] skill;
6 |
7 | function addEmployeeToSkill(string memory _name, address _employee) public {
8 | if (skillmap[_name].length == 0) {
9 | skill.push(_name);
10 | }
11 | skillmap[_name].push(_employee);
12 | }
13 |
14 | function getSkillLength() public view returns (uint256) {
15 | return skill.length;
16 | }
17 |
18 | function getSkillsByIndex(uint256 index) public view returns (string memory) {
19 | return skill[index];
20 | }
21 |
22 | function getTotalEmployeeInSkillByIndex(uint256 index)
23 | public
24 | view
25 | returns (uint256)
26 | {
27 | return skillmap[skill[index]].length;
28 | }
29 |
30 | function getTotalEmployeeInSkillByName(string memory _name)
31 | public
32 | view
33 | returns (uint256)
34 | {
35 | return skillmap[_name].length;
36 | }
37 |
38 | function getEmployeeInSkillByIndex(uint256 skill_index, uint256 emp_index)
39 | public
40 | view
41 | returns (address)
42 | {
43 | return skillmap[skill[skill_index]][emp_index];
44 | }
45 |
46 | function getEmployeeBySkillName(string memory _name, uint256 emp_index)
47 | public
48 | view
49 | returns (address)
50 | {
51 | return skillmap[_name][emp_index];
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/Search.css:
--------------------------------------------------------------------------------
1 | .searchbar > .results > .result > .content > .title {
2 | float: right !important;
3 | font-weight: 400 !important;
4 | }
5 |
6 | .search-ele {
7 | color: black;
8 | }
9 |
10 | .search-ele > div:nth-child(1) > span {
11 | display: block;
12 | }
13 |
14 | .search-ele > small {
15 | display: block;
16 | }
17 |
18 | .ui.selection.dropdown {
19 | border-radius: 7px !important;
20 | background: #1e2022ea !important;
21 | border: 1px solid white !important;
22 | box-shadow: 0px 0px 1px 0px white !important;
23 | color: white !important;
24 | }
25 |
26 | .ui.default.dropdown:not(.button) > .text,
27 | .ui.dropdown:not(.button) > .default.text {
28 | color: white !important;
29 | }
30 |
31 | .ui.selection.active.dropdown .menu {
32 | background: #1e2022ea !important;
33 | color: white !important;
34 | border-bottom-left-radius: 7px !important;
35 | border-bottom-right-radius: 7px !important;
36 | box-shadow: 0px 0px 1px 0px white !important;
37 | }
38 |
39 | .ui.selection.dropdown .menu > .item {
40 | color: white !important;
41 | border-top: 1px solid white !important;
42 | }
43 |
44 | .ui.dropdown .menu .selected.item,
45 | .ui.dropdown.selected {
46 | color: #1e2022ea !important;
47 | background: white !important;
48 | }
49 |
50 | .ui.selection.visible.dropdown > .text:not(.default) {
51 | color: white !important;
52 | }
53 |
54 | .visible .menu .transition > .selected .item > .text {
55 | color: white !important;
56 | }
57 |
--------------------------------------------------------------------------------
/src/pages/GetRoutes/Employee.css:
--------------------------------------------------------------------------------
1 | .personal-info {
2 | background: #393b3fa6 !important;
3 | border-radius: 7px !important;
4 | border: 1px solid white !important;
5 | box-shadow: 0px 0px 1px 0px white !important;
6 | color: white !important;
7 | width: 100% !important;
8 | }
9 |
10 | .personal-info > .content > .header {
11 | display: flex !important;
12 | justify-content: space-between !important;
13 | flex-wrap: wrap !important;
14 | color: white !important;
15 | }
16 |
17 | .personal-info > .content > .header > small {
18 | font-size: 12px !important;
19 | font-weight: 600 !important;
20 | font-style: italic;
21 | }
22 |
23 | .employee-des {
24 | background: #393b3fa6 !important;
25 | border-radius: 7px !important;
26 | border: 1px solid white !important;
27 | box-shadow: 0px 0px 1px 0px white !important;
28 | color: white !important;
29 | width: 100% !important;
30 | }
31 |
32 | .employee-des > .content > .header {
33 | display: flex !important;
34 | justify-content: space-between !important;
35 | flex-wrap: wrap !important;
36 | color: white !important;
37 | }
38 |
39 | .employee-des > .content > .header > small {
40 | font-size: 12px !important;
41 | font-weight: 600 !important;
42 | font-style: italic;
43 | }
44 |
45 | .certification-container {
46 | display: flex;
47 | justify-content: space-between;
48 | margin-bottom: 18px;
49 | }
50 |
51 | .skill-height-container {
52 | max-height: 20rem;
53 | overflow: auto;
54 | }
55 |
--------------------------------------------------------------------------------
/src/pages/Employee/Employee.css:
--------------------------------------------------------------------------------
1 | .personal-info {
2 | background: #393b3fa6 !important;
3 | border-radius: 7px !important;
4 | border: 1px solid white !important;
5 | box-shadow: 0px 0px 1px 0px white !important;
6 | color: white !important;
7 | width: 100% !important;
8 | }
9 |
10 | .personal-info > .content > .header {
11 | display: flex !important;
12 | justify-content: space-between !important;
13 | flex-wrap: wrap !important;
14 | color: white !important;
15 | }
16 |
17 | .personal-info > .content > .header > small {
18 | font-size: 12px !important;
19 | font-weight: 600 !important;
20 | font-style: italic;
21 | }
22 |
23 | .employee-des {
24 | background: #393b3fa6 !important;
25 | border-radius: 7px !important;
26 | border: 1px solid white !important;
27 | box-shadow: 0px 0px 1px 0px white !important;
28 | color: white !important;
29 | width: 100% !important;
30 | }
31 |
32 | .employee-des > .content > .header {
33 | display: flex !important;
34 | justify-content: space-between !important;
35 | flex-wrap: wrap !important;
36 | color: white !important;
37 | }
38 |
39 | .employee-des > .content > .header > small {
40 | font-size: 12px !important;
41 | font-weight: 600 !important;
42 | font-style: italic;
43 | }
44 |
45 | .certification-container {
46 | display: flex;
47 | justify-content: space-between;
48 | margin-bottom: 18px;
49 | }
50 |
51 | .skill-height-container {
52 | max-height: 36rem !important;
53 | overflow: auto;
54 | }
55 |
--------------------------------------------------------------------------------
/src/components/GenererateQR.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import QRCode from "qrcode";
3 | import "./Modals.css";
4 | import { Button, Header, Modal } from "semantic-ui-react";
5 |
6 | export default class GenererateQR extends Component {
7 | state = {
8 | qr: "",
9 | };
10 |
11 | componentDidMount = async () => {
12 | const web3 = window.web3;
13 | const accounts = await web3.eth.getAccounts();
14 | try {
15 | const res = await QRCode.toDataURL(accounts[0]);
16 | this.setState({ qr: res });
17 | } catch (err) {
18 | console.log(err);
19 | }
20 | };
21 |
22 | render() {
23 | return (
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | this.props.closeQRModal()}
44 | />
45 |
46 |
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/EmployeeCard.css:
--------------------------------------------------------------------------------
1 | .employee-card {
2 | width: 70% !important;
3 | margin-left: auto !important;
4 | margin-right: auto !important;
5 | background: #393b3fa6 !important;
6 | border-radius: 7px !important;
7 | border: 1px solid white !important;
8 | box-shadow: 0px 0px 2px 0px white !important;
9 | color: white !important;
10 | margin-bottom: 2rem !important;
11 | }
12 |
13 | .employee-card:hover {
14 | transform: scale(1.03, 1.03);
15 | }
16 |
17 | .employee-card > .content > .header {
18 | display: flex !important;
19 | justify-content: space-between !important;
20 | flex-wrap: wrap !important;
21 | color: white !important;
22 | }
23 |
24 | .employee-card > .content > .header > small {
25 | font-size: 12px !important;
26 | font-weight: 600 !important;
27 | font-style: italic;
28 | }
29 |
30 | @media only screen and (max-width: 800px) {
31 | .employee-card {
32 | width: 100% !important;
33 | }
34 | }
35 |
36 | .skill-design {
37 | width: fit-content;
38 | border-radius: 30px;
39 | padding: 3px;
40 | padding-left: 12px;
41 | padding-right: 12px;
42 | margin: 5px;
43 | }
44 |
45 | .skill-holder {
46 | display: flex;
47 | flex-wrap: wrap;
48 | justify-items: flex-start;
49 | }
50 |
51 | .readopenclose {
52 | color: #c5c6c7;
53 | float: right;
54 | cursor: pointer;
55 | }
56 |
57 | .certification-design {
58 | display: flex;
59 | justify-content: space-between;
60 | margin: 10px;
61 | }
62 |
63 | .education-design {
64 | display: flex;
65 | justify-content: space-between;
66 | margin: 10px;
67 | }
68 |
69 | .workexp-design {
70 | display: flex;
71 | justify-content: space-between;
72 | margin: 10px;
73 | }
74 |
--------------------------------------------------------------------------------
/src/pages/Admin/AllEmployees.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import EmployeeCard from "../../components/EmployeeCard";
4 | import "./Admin.css";
5 | import Admin from "../../abis/Admin.json";
6 | import LoadComp from "../../components/LoadComp";
7 |
8 | export default class AllEmployees extends Component {
9 | state = {
10 | employees: [],
11 | loadcomp: false,
12 | };
13 |
14 | componentDidMount = async () => {
15 | this.setState({ loadcomp: true });
16 | const web3 = window.web3;
17 | const networkId = await web3.eth.net.getId();
18 | const AdminData = await Admin.networks[networkId];
19 | if (AdminData) {
20 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
21 | const employeeCount = await admin?.methods.employeeCount().call();
22 |
23 | const employees = await Promise.all(
24 | Array(parseInt(employeeCount))
25 | .fill()
26 | .map((ele, index) =>
27 | admin.methods.getEmployeeContractByIndex(index).call()
28 | )
29 | );
30 | this.setState({ employees });
31 | } else {
32 | toast.error("The Admin Contract does not exist on this network!");
33 | }
34 | this.setState({ loadcomp: false });
35 | };
36 |
37 | render() {
38 | return this.state.loadcomp ? (
39 |
40 | ) : (
41 |
42 |
All Registered Employees
43 |
44 | {this.state.employees?.map((employee, index) => (
45 |
46 | ))}
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/EndorsePage.css:
--------------------------------------------------------------------------------
1 | .endorse-section {
2 | position: fixed;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | -webkit-transform: translate(-50%, -50%);
7 | -moz-transform: translate(-50%, -50%);
8 | -o-transform: translate(-50%, -50%);
9 | -ms-transform: translate(-50%, -50%);
10 | margin-top: 40px;
11 | }
12 |
13 | .form-inputs > input,
14 | .form-inputs > .input > input,
15 | .form-inputs > textarea {
16 | border-radius: 7px !important;
17 | background: #1e2022ea !important;
18 | border: 1px solid white !important;
19 | box-shadow: 0px 0px 1px 0px white !important;
20 | color: white !important;
21 | }
22 |
23 | .form-inputs > input::placeholder {
24 | color: white !important;
25 | opacity: 0.7;
26 | }
27 |
28 | .form-inputs > input::selection {
29 | color: white !important;
30 | }
31 |
32 | .form-inputs > input:focus {
33 | box-shadow: 0px 0px 2px 0px white !important;
34 | }
35 |
36 | .button-css {
37 | border-radius: 10px !important;
38 | color: white !important;
39 | background: #1e2022ea !important;
40 | border: 2px solid white !important;
41 | box-shadow: 0px 0px 2px 0px white !important;
42 | text-align: center;
43 | }
44 |
45 | .button-css:hover {
46 | background: white !important;
47 | color: #1e2022ea !important;
48 | }
49 |
50 | .close-button {
51 | border-radius: 10px !important;
52 | color: #c5c6c7 !important;
53 | background: #1e2022ea !important;
54 | border: 2px solid #c5c6c7 !important;
55 | box-shadow: 0px 0px 1px 0px #c5c6c7 !important;
56 | text-align: center;
57 | }
58 |
59 | .close-button:hover {
60 | background: #c5c6c7 !important;
61 | color: #1e2022ea !important;
62 | }
63 |
64 | .pos-middle-qr {
65 | text-align: center;
66 | }
67 |
--------------------------------------------------------------------------------
/src/pages/Admin/AllOrganizationEndorser.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import Admin from "../../abis/Admin.json";
4 | import LoadComp from "../../components/LoadComp";
5 | import OrgEndCard from "../../components/OrgEndCard";
6 |
7 | export default class AllOrganizationEndorser extends Component {
8 | state = {
9 | orgends: [],
10 | loadcomp: false,
11 | };
12 |
13 | componentDidMount = async () => {
14 | this.setState({ loadcomp: true });
15 | const web3 = window.web3;
16 | const networkId = await web3.eth.net.getId();
17 | const AdminData = await Admin.networks[networkId];
18 | if (AdminData) {
19 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
20 | const orgendCount = await admin?.methods
21 | .OrganizationEndorserCount()
22 | .call();
23 | const orgends = await Promise.all(
24 | Array(parseInt(orgendCount))
25 | .fill()
26 | .map((ele, index) =>
27 | admin.methods.getOrganizationContractByIndex(index).call()
28 | )
29 | );
30 | this.setState({ orgends });
31 | } else {
32 | toast.error("The Admin Contract does not exist on this network!");
33 | }
34 | this.setState({ loadcomp: false });
35 | };
36 |
37 | render() {
38 | return this.state.loadcomp ? (
39 |
40 | ) : (
41 |
42 |
All Registered Organization-Endorser
43 |
44 | {this.state.orgends?.map((orgend, index) => (
45 |
46 | ))}
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "skillset-verified",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.11.4",
7 | "@testing-library/react": "^11.1.0",
8 | "@testing-library/user-event": "^12.1.10",
9 | "@truffle/hdwallet-provider": "^1.4.1",
10 | "babel-polyfill": "^6.26.0",
11 | "babel-preset-env": "^1.7.0",
12 | "babel-preset-es2015": "^6.24.1",
13 | "babel-preset-stage-2": "^6.24.1",
14 | "babel-preset-stage-3": "^6.24.1",
15 | "babel-register": "^6.26.0",
16 | "chai": "^4.3.4",
17 | "chai-as-promised": "^7.1.1",
18 | "chai-bignumber": "^3.0.0",
19 | "chart.js": "^3.5.1",
20 | "firebase": "^8.6.5",
21 | "lodash": "^4.17.21",
22 | "qrcode": "^1.4.4",
23 | "react": "^17.0.2",
24 | "react-chartjs-2": "^3.0.5",
25 | "react-circular-progressbar": "^2.0.4",
26 | "react-dom": "^17.0.2",
27 | "react-qr-reader": "^2.2.1",
28 | "react-redux": "^7.2.5",
29 | "react-router-dom": "^5.3.0",
30 | "react-scripts": "4.0.3",
31 | "react-toastify": "^7.0.4",
32 | "redux": "^4.1.0",
33 | "redux-thunk": "^2.3.0",
34 | "semantic-ui-css": "^2.4.1",
35 | "semantic-ui-react": "^2.0.3",
36 | "truffle": "^5.1.39",
37 | "truffle-contract-size": "^2.0.1",
38 | "web-vitals": "^1.0.1",
39 | "web3": "^1.2.11"
40 | },
41 | "scripts": {
42 | "start": "react-scripts start",
43 | "build": "react-scripts build",
44 | "test": "react-scripts test",
45 | "eject": "react-scripts eject"
46 | },
47 | "eslintConfig": {
48 | "extends": [
49 | "react-app",
50 | "react-app/jest"
51 | ]
52 | },
53 | "browserslist": {
54 | "production": [
55 | ">0.2%",
56 | "not dead",
57 | "not op_mini all"
58 | ],
59 | "development": [
60 | "last 1 chrome version",
61 | "last 1 firefox version",
62 | "last 1 safari version"
63 | ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-ashy-ocean-068119800.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ASHY_OCEAN_068119800 }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "/" # App source code path
31 | api_location: "api" # Api source code path - optional
32 | output_location: "build" # Built app content directory - optional
33 | ###### End of Repository/Build Configurations ######
34 |
35 | close_pull_request_job:
36 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
37 | runs-on: ubuntu-latest
38 | name: Close Pull Request Job
39 | steps:
40 | - name: Close Pull Request
41 | id: closepullrequest
42 | uses: Azure/static-web-apps-deploy@v1
43 | with:
44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ASHY_OCEAN_068119800 }}
45 | action: "close"
46 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-kind-grass-06d9d2100.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_GRASS_06D9D2100 }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "/" # App source code path
31 | api_location: "api" # Api source code path - optional
32 | output_location: "build" # Built app content directory - optional
33 | ###### End of Repository/Build Configurations ######
34 |
35 | close_pull_request_job:
36 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
37 | runs-on: ubuntu-latest
38 | name: Close Pull Request Job
39 | steps:
40 | - name: Close Pull Request
41 | id: closepullrequest
42 | uses: Azure/static-web-apps-deploy@v1
43 | with:
44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_GRASS_06D9D2100 }}
45 | action: "close"
46 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-nice-cliff-0fcb7af00.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_NICE_CLIFF_0FCB7AF00 }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "build" # App source code path
31 | api_location: "api" # Api source code path - optional
32 | output_location: "/build" # Built app content directory - optional
33 | ###### End of Repository/Build Configurations ######
34 |
35 | close_pull_request_job:
36 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
37 | runs-on: ubuntu-latest
38 | name: Close Pull Request Job
39 | steps:
40 | - name: Close Pull Request
41 | id: closepullrequest
42 | uses: Azure/static-web-apps-deploy@v1
43 | with:
44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_NICE_CLIFF_0FCB7AF00 }}
45 | action: "close"
46 |
--------------------------------------------------------------------------------
/.github/workflows/azure-static-web-apps-agreeable-pebble-0716f3500.yml:
--------------------------------------------------------------------------------
1 | name: Azure Static Web Apps CI/CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types: [opened, synchronize, reopened, closed]
9 | branches:
10 | - main
11 |
12 | jobs:
13 | build_and_deploy_job:
14 | if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
15 | runs-on: ubuntu-latest
16 | name: Build and Deploy Job
17 | steps:
18 | - uses: actions/checkout@v2
19 | with:
20 | submodules: true
21 | - name: Build And Deploy
22 | id: builddeploy
23 | uses: Azure/static-web-apps-deploy@v1
24 | with:
25 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_PEBBLE_0716F3500 }}
26 | repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
27 | action: "upload"
28 | ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
29 | # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
30 | app_location: "/" # App source code path
31 | api_location: "api" # Api source code path - optional
32 | output_location: "build" # Built app content directory - optional
33 | ###### End of Repository/Build Configurations ######
34 |
35 | close_pull_request_job:
36 | if: github.event_name == 'pull_request' && github.event.action == 'closed'
37 | runs-on: ubuntu-latest
38 | name: Close Pull Request Job
39 | steps:
40 | - name: Close Pull Request
41 | id: closepullrequest
42 | uses: Azure/static-web-apps-deploy@v1
43 | with:
44 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_PEBBLE_0716F3500 }}
45 | action: "close"
46 |
--------------------------------------------------------------------------------
/src/pages/Employee/UpdateProfile.css:
--------------------------------------------------------------------------------
1 | .add-button {
2 | float: right;
3 | height: 40px;
4 | width: 40px;
5 | display: grid;
6 | justify-items: center;
7 | align-items: center;
8 | border: 2px solid rgb(255, 255, 255);
9 | background-color: #393b3fa6;
10 | border-radius: 50%;
11 | box-shadow: inset 0px 0px 10px #c5c6c7;
12 | cursor: pointer;
13 | }
14 |
15 | .add-button:hover {
16 | transform: scale(1.1, 1.1);
17 | box-shadow: inset 0px 0px 20px white;
18 | }
19 |
20 | .edit-heading {
21 | display: flex;
22 | justify-content: space-between;
23 | width: 100%;
24 | margin-bottom: 8px;
25 | }
26 |
27 | .delete-button-visiblility {
28 | margin-left: 10px;
29 | color: white;
30 | cursor: pointer;
31 | }
32 |
33 | .delete-button-visiblility:hover {
34 | transform: scale(1.1, 1.1);
35 | }
36 |
37 | .endorsement-req-button {
38 | border: 1px solid white;
39 | border-radius: 7px;
40 | text-align: center;
41 | margin-top: 5px;
42 | padding: 5px;
43 | cursor: pointer;
44 | }
45 |
46 | .endorsement-req-button:hover {
47 | transform: scale(1.02, 1.02);
48 | }
49 |
50 | .sidechat-container {
51 | margin-top: 2rem;
52 | margin-left: 1rem;
53 | }
54 |
55 | .notifications {
56 | background: rgba(31, 30, 30, 0.581);
57 | width: 85%;
58 | margin-left: auto;
59 | margin-right: auto;
60 | height: 80vh;
61 | margin-top: 40px;
62 | border-radius: 10px;
63 | border: 1px solid white;
64 | box-shadow: inset 0 0 3px 0 white;
65 | }
66 |
67 | .sidechat-body {
68 | overflow: auto !important;
69 | }
70 |
71 | .notification-sidechat {
72 | color: white !important;
73 | }
74 |
75 | .notification-sidechat-subheading {
76 | color: #c5c6c7 !important;
77 | }
78 |
79 | .header-row > th {
80 | border-bottom: 1px solid white !important;
81 | }
82 |
83 | .row-cell-container {
84 | cursor: pointer;
85 | }
86 |
87 | .header-row-cell {
88 | border-bottom: 1px solid #c5c6c7 !important;
89 | }
90 |
91 | .row-cell-container :hover {
92 | transform: scale(1.01, 1.01);
93 | background: rgba(31, 30, 30, 0.1);
94 | }
95 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/Organization.css:
--------------------------------------------------------------------------------
1 | .org-card {
2 | width: 70% !important;
3 | margin-left: auto !important;
4 | margin-right: auto !important;
5 | background: #393b3fa6 !important;
6 | border-radius: 7px !important;
7 | border: 1px solid white !important;
8 | box-shadow: 2px 0px 3px 1px white !important;
9 | color: white !important;
10 | }
11 |
12 | .add-employee {
13 | padding: 10px;
14 | float: right;
15 | display: grid;
16 | justify-items: center;
17 | align-items: center;
18 | border: 2px solid rgb(255, 255, 255);
19 | background-color: #393b3fa6;
20 | border-radius: 10px;
21 | box-shadow: inset 0px 0px 10px #c5c6c7;
22 | cursor: pointer;
23 | margin-top: 16px;
24 | color: white;
25 | padding-bottom: 12px;
26 | margin-top: -5px;
27 | }
28 |
29 | .add-employee:hover {
30 | transform: scale(1.1, 1.1);
31 | box-shadow: inset 0px 0px 20px white;
32 | }
33 |
34 | .org-card-heading {
35 | font-family: "Arvo", serif !important;
36 | color: white;
37 | font-size: 25px;
38 | font-weight: 500;
39 | }
40 |
41 | .endorsement-req-button {
42 | border: 1px solid white;
43 | border-radius: 7px;
44 | text-align: center;
45 | margin-top: 5px;
46 | padding: 5px;
47 | cursor: pointer;
48 | }
49 |
50 | .endorsement-req-button:hover {
51 | transform: scale(1.02, 1.02);
52 | }
53 |
54 | .sidechat-container {
55 | margin-top: 2rem;
56 | margin-left: 1rem;
57 | }
58 |
59 | .notifications {
60 | background: rgba(31, 30, 30, 0.581);
61 | width: 85%;
62 | margin-left: auto;
63 | margin-right: auto;
64 | height: 80vh;
65 | margin-top: 40px;
66 | border-radius: 10px;
67 | border: 1px solid white;
68 | box-shadow: inset 0 0 3px 0 white;
69 | }
70 |
71 | .sidechat-body {
72 | overflow: auto !important;
73 | }
74 |
75 | .notification-sidechat {
76 | color: white !important;
77 | }
78 |
79 | .notification-sidechat-subheading {
80 | color: #c5c6c7 !important;
81 | }
82 |
83 | .header-row > th {
84 | border-bottom: 1px solid white !important;
85 | }
86 |
87 | .row-cell-container {
88 | cursor: pointer;
89 | }
90 |
91 | .header-row-cell {
92 | border-bottom: 1px solid #c5c6c7 !important;
93 | }
94 |
95 | .row-cell-container :hover {
96 | transform: scale(1.01, 1.01);
97 | background: rgba(31, 30, 30, 0.1);
98 | }
99 |
--------------------------------------------------------------------------------
/src/components/OrgEndCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "./OrgEndCard.css";
3 | import OrgEnd from "../abis/OrganizationEndorser.json";
4 | import { Card } from "semantic-ui-react";
5 |
6 | export default class OrgEndCard extends Component {
7 | state = {
8 | orgEndInfo: {},
9 | allEmployeesInOrg: [],
10 | };
11 |
12 | componentDidMount = async () => {
13 | const web3 = window.web3;
14 | const OrgEndContract = await new web3.eth.Contract(
15 | OrgEnd.abi,
16 | this.props.OrgEndContractAddress
17 | );
18 |
19 | const orgEndData = await OrgEndContract.methods
20 | .getOrganizationInfo()
21 | .call();
22 | const orgEndInfo = {
23 | ethAddress: orgEndData[1],
24 | name: orgEndData[0],
25 | location: orgEndData[2],
26 | description: orgEndData[3],
27 | };
28 |
29 | const employeeCount = await OrgEndContract.methods.totalEmployees().call();
30 |
31 | const allEmployeesInOrg = await Promise.all(
32 | Array(parseInt(employeeCount))
33 | .fill()
34 | .map((ele, index) =>
35 | OrgEndContract.methods.getEmployeeByIndex(index).call()
36 | )
37 | );
38 | this.setState({ orgEndInfo, allEmployeesInOrg });
39 | };
40 |
41 | render() {
42 | return (
43 |
44 |
45 |
46 | {this.state.orgEndInfo?.name}
47 | {this.state.orgEndInfo?.ethAddress}
48 |
49 |
50 |
51 |
52 | Location :
53 |
54 | {this.state.orgEndInfo?.location}
55 |
56 |
57 |
58 |
59 |
60 |
Description :
61 |
62 | {this.state.orgEndInfo?.description}
63 |
64 |
65 |
66 |
67 |
68 | Employee Count:
69 |
70 | {this.state.allEmployeesInOrg?.length}
71 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/components/CodeforcesGraph.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { Line } from "react-chartjs-2";
3 |
4 | function CodeforcesGraph() {
5 | const [data, setdata] = useState({});
6 | const [mxRating, setmxRating] = useState(0);
7 |
8 | const options = {
9 | legend: {
10 | display: false,
11 | },
12 | elements: {
13 | points: {
14 | radius: 0,
15 | },
16 | },
17 | maintainAspectRatio: false,
18 | scales: {
19 | yAxes: [
20 | {
21 | gridLines: {
22 | display: false,
23 | },
24 | ticks: {
25 | beginAtZero: true,
26 | },
27 | },
28 | ],
29 | },
30 | };
31 |
32 | useEffect(() => {
33 | const fetchdata = async () => {
34 | fetch("https://codeforces.com/api/user.rating?handle=Paladin09")
35 | .then((res) => res.json())
36 | .then((res) => {
37 | if (res.status === "OK" && res.result.length > 1) {
38 | var newarr = [];
39 | var mx = 0;
40 | res.result.forEach((data) => {
41 | newarr.push(data.newRating);
42 | if (data.newRating && data.newRating >= mx) {
43 | mx = data.newRating;
44 | }
45 | });
46 | setmxRating(mx);
47 | var newlabels = [...Array(res.result.length).keys()];
48 | setdata({
49 | labels: newlabels,
50 | datasets: [
51 | {
52 | label: "Ratings",
53 | data: newarr,
54 | backgroundColor: "white",
55 | borderColor: "rgba(255,255,255,0.3)",
56 | fill: false,
57 | },
58 | ],
59 | });
60 | }
61 | })
62 | .catch((err) => {
63 | console.log(err);
64 | });
65 | };
66 | fetchdata();
67 | return () => {
68 | //
69 | };
70 | }, []);
71 |
72 | return (
73 | <>
74 |
75 |
76 | Codeforces Ratings:{" "}
77 |
{mxRating}
{" "}
78 |
79 | (max-rating)
80 |
81 |
82 |
83 |
84 |
85 | >
86 | );
87 | }
88 |
89 | export default CodeforcesGraph;
90 |
--------------------------------------------------------------------------------
/src/components/Modals.css:
--------------------------------------------------------------------------------
1 | .modal-des {
2 | background: #1e2022ea !important;
3 | border-radius: 10px !important;
4 | color: #c5c6c7 !important;
5 | border: 1px solid white !important;
6 | box-shadow: 0px 0px 3px 0px white !important;
7 | }
8 |
9 | .modal-heading {
10 | background: #1e2022ea !important;
11 | border-top-left-radius: 10px !important;
12 | border-top-right-radius: 10px !important;
13 | font-family: "Arvo", serif !important;
14 | color: white !important;
15 | font-size: 2rem !important;
16 | font-weight: 500 !important;
17 | width: 100% !important;
18 | text-align: center;
19 | }
20 |
21 | .modal-content {
22 | background: #1e2022ea !important;
23 | }
24 |
25 | .modal-actions {
26 | background: #1e2022ea !important;
27 | border-bottom-left-radius: 10px !important;
28 | border-bottom-right-radius: 10px !important;
29 | }
30 |
31 | .horizontal-line {
32 | border: none;
33 | border-top: 2px solid white;
34 | }
35 |
36 | .form-inputs > input {
37 | border-radius: 7px !important;
38 | background: #1e2022ea !important;
39 | border: 1px solid white !important;
40 | box-shadow: 0px 0px 1px 0px white !important;
41 | color: white !important;
42 | }
43 |
44 | .form-inputs > input::placeholder {
45 | color: white !important;
46 | opacity: 0.7;
47 | }
48 |
49 | .form-inputs > input::selection {
50 | color: white !important;
51 | }
52 |
53 | .form-inputs > input:focus {
54 | box-shadow: 0px 0px 2px 0px white !important;
55 | }
56 |
57 | .button-css {
58 | border-radius: 10px !important;
59 | color: white !important;
60 | background: #1e2022ea !important;
61 | border: 2px solid white !important;
62 | box-shadow: 0px 0px 2px 0px white !important;
63 | text-align: center;
64 | }
65 |
66 | .button-css:hover {
67 | background: white !important;
68 | color: #1e2022ea !important;
69 | }
70 |
71 | .close-button {
72 | border-radius: 10px !important;
73 | color: #c5c6c7 !important;
74 | background: #1e2022ea !important;
75 | border: 2px solid #c5c6c7 !important;
76 | box-shadow: 0px 0px 1px 0px #c5c6c7 !important;
77 | text-align: center;
78 | }
79 |
80 | .close-button:hover {
81 | background: #c5c6c7 !important;
82 | color: #1e2022ea !important;
83 | }
84 |
85 | .pos-middle-qr {
86 | text-align: center;
87 | }
88 |
89 | .design-info-table {
90 | background: #1e2022ea !important;
91 | border: 1px solid white !important;
92 | padding: 5px;
93 | color: white !important;
94 | box-shadow: inset 0 0 3px white !important;
95 | }
96 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/SearchEmp.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Employee from "../abis/Employee.json";
3 | import Admin from "../abis/Admin.json";
4 | import { toast } from "react-toastify";
5 | import { Dimmer, Loader } from "semantic-ui-react";
6 | import { withRouter } from "react-router-dom";
7 |
8 | class SearchEmp extends Component {
9 | state = {
10 | employeedata: {},
11 | loading: false,
12 | employeeContractAddress: "",
13 | };
14 |
15 | componentDidMount = async () => {
16 | this.setState({ loading: true });
17 | const empAddress = this.props.emp;
18 | const web3 = window.web3;
19 | const networkId = await web3.eth.net.getId();
20 | const AdminData = await Admin.networks[networkId];
21 | if (AdminData) {
22 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
23 | const employeeContractAddress = await admin.methods
24 | ?.getEmployeeContractByAddress(empAddress)
25 | .call();
26 | const EmployeeContract = await new web3.eth.Contract(
27 | Employee.abi,
28 | employeeContractAddress
29 | );
30 | const employeedata = await EmployeeContract.methods
31 | .getEmployeeInfo()
32 | .call();
33 | const newEmployedata = {
34 | ethAddress: employeedata[0],
35 | name: employeedata[1],
36 | location: employeedata[2],
37 | description: employeedata[3],
38 | overallEndorsement: employeedata[4],
39 | endorsecount: employeedata[5],
40 | };
41 | this.setState({ employeedata: newEmployedata, employeeContractAddress });
42 | } else {
43 | toast.error("The Admin Contract does not exist on this network!");
44 | }
45 | this.setState({ loading: false });
46 | };
47 |
48 | toRoute = () => {
49 | this.props.history.push(
50 | `/getemployee/${this.state.employeeContractAddress}`
51 | );
52 | window.location.reload(false);
53 | };
54 |
55 | render() {
56 | return this.state.loading ? (
57 |
58 |
59 |
60 | ) : (
61 |
66 |
67 | {this.state?.employeedata?.name}
68 | {this.state?.employeedata?.location}
69 |
70 |
{this.state?.employeedata?.ethAddress}
71 |
72 |
{this.state?.employeedata?.description}
73 |
74 | );
75 | }
76 | }
77 |
78 | export default withRouter(SearchEmp);
79 |
--------------------------------------------------------------------------------
/src/components/LoadComp.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./LoadComp.css";
3 |
4 | function LoadComp() {
5 | return (
6 |
7 |
21 |
22 |
23 |
31 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
42 | export default LoadComp;
43 |
--------------------------------------------------------------------------------
/src/pages/NoRole/NoRole.css:
--------------------------------------------------------------------------------
1 | .norole {
2 | text-align: center;
3 | margin-top: 40px;
4 | }
5 |
6 | .norole > .card-style {
7 | background: #1e2022ea !important;
8 | border-radius: 7px !important;
9 | color: #c5c6c7 !important;
10 | min-width: 360px;
11 | border: 1px solid white !important;
12 | box-shadow: 0px 0px 2px 0px white !important;
13 | margin-left: auto !important;
14 | margin-right: auto !important;
15 | }
16 |
17 | .card-heading {
18 | font-family: "Arvo", serif !important;
19 | color: white;
20 | font-size: 2rem;
21 | font-weight: 500;
22 | width: 100%;
23 | text-align: center;
24 | }
25 |
26 | .norole-heading-subtext {
27 | color: #c5c6c7;
28 | font-size: 12px;
29 | font-weight: 500;
30 | }
31 |
32 | .horizontal-line {
33 | border: none;
34 | border-top: 2px solid white;
35 | }
36 |
37 | .form-inputs-admin > input,
38 | .form-inputs-admin > textarea {
39 | border-radius: 7px !important;
40 | background: #1e2022ea !important;
41 | border: 1px solid white !important;
42 | box-shadow: 0px 0px 1px 0px white !important;
43 | color: white !important;
44 | }
45 |
46 | .form-inputs-admin > input::placeholder,
47 | .form-inputs-admin > textarea::placeholder {
48 | color: white !important;
49 | opacity: 0.7;
50 | }
51 |
52 | .form-inputs-admin > input::selection {
53 | color: white !important;
54 | }
55 |
56 | .form-inputs-admin > input:focus {
57 | box-shadow: 0px 0px 2px 0px white !important;
58 | }
59 |
60 | .ui.selection.dropdown {
61 | border-radius: 7px !important;
62 | background: #1e2022ea !important;
63 | border: 1px solid white !important;
64 | box-shadow: 0px 0px 1px 0px white !important;
65 | color: white !important;
66 | }
67 |
68 | .ui.default.dropdown:not(.button) > .text,
69 | .ui.dropdown:not(.button) > .default.text {
70 | color: white !important;
71 | }
72 |
73 | .ui.selection.active.dropdown .menu {
74 | background: #1e2022ea !important;
75 | color: white !important;
76 | border-bottom-left-radius: 7px !important;
77 | border-bottom-right-radius: 7px !important;
78 | box-shadow: 0px 0px 1px 0px white !important;
79 | }
80 |
81 | .ui.selection.dropdown .menu > .item {
82 | color: white !important;
83 | border-top: 1px solid white !important;
84 | }
85 |
86 | .ui.dropdown .menu .selected.item,
87 | .ui.dropdown.selected {
88 | color: #1e2022ea !important;
89 | background: white !important;
90 | }
91 |
92 | .ui.selection.visible.dropdown > .text:not(.default) {
93 | color: white !important;
94 | }
95 |
96 | .button-holder {
97 | text-align: center;
98 | }
99 |
100 | .button-css-admin {
101 | border-radius: 10px !important;
102 | color: white !important;
103 | background: #1e2022ea !important;
104 | border: 2px solid white !important;
105 | box-shadow: 0px 0px 2px 0px white !important;
106 | text-align: center;
107 | }
108 |
109 | .button-css-admin:hover {
110 | background: white !important;
111 | color: #1e2022ea !important;
112 | }
113 |
--------------------------------------------------------------------------------
/src/pages/GetRoutes/GetOrg.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Organization from "../../abis/OrganizationEndorser.json";
3 | import Admin from "../../abis/Admin.json";
4 | import { toast } from "react-toastify";
5 | import OrgEndCard from "../../components/OrgEndCard";
6 | import EmployeeCard from "../../components/EmployeeCard";
7 | import "./GetOrg.css";
8 | import LoadComp from "../../components/LoadComp";
9 | import { withRouter } from "react-router-dom";
10 |
11 | class GetOrg extends Component {
12 | state = {
13 | orgcontractAddress: "",
14 | employees: [],
15 | employeemodal: false,
16 | loadcomp: false,
17 | };
18 |
19 | componentDidMount = async () => {
20 | this.setState({ loadcomp: true });
21 | await this.getEmployees();
22 | this.setState({ loadcomp: false });
23 | };
24 |
25 | getEmployees = async () => {
26 | const web3 = window.web3;
27 | const networkId = await web3.eth.net.getId();
28 | const AdminData = await Admin.networks[networkId];
29 | const orgAddress = this.props.match.params.orgAddress;
30 | if (!orgAddress) {
31 | this.props.history.push("/");
32 | return;
33 | }
34 | if (AdminData) {
35 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
36 | const orgContractAddress = await admin?.methods
37 | ?.getOrganizationContractByAddress(orgAddress)
38 | .call();
39 | const orgContract = await new web3.eth.Contract(
40 | Organization.abi,
41 | orgContractAddress
42 | );
43 |
44 | const employeeCount = await orgContract?.methods?.totalEmployees().call();
45 |
46 | const employees = await Promise.all(
47 | Array(parseInt(employeeCount))
48 | .fill()
49 | .map(async (ele, index) => {
50 | const employee = await orgContract?.methods
51 | ?.getEmployeeByIndex(index)
52 | .call();
53 | return admin.methods.getEmployeeContractByAddress(employee).call();
54 | })
55 | );
56 |
57 | this.setState({ orgContractAddress, employees });
58 | } else {
59 | toast.error("The Admin Contract does not exist on this network!");
60 | }
61 | };
62 |
63 | render() {
64 | return this.state.loadcomp ? (
65 |
66 | ) : (
67 |
68 | {this.state.orgContractAddress && (
69 |
70 | )}
71 |
72 |
73 |
76 |
Employees in the organization
77 |
78 |
79 | {this.state.employees?.map((employee, index) => (
80 |
81 | ))}
82 |
83 |
84 |
85 | );
86 | }
87 | }
88 |
89 | export default withRouter(GetOrg);
90 |
--------------------------------------------------------------------------------
/src/contracts/Admin.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0 <0.9.0;
2 | import "./Employee.sol";
3 | import "./OrganizationEndorser.sol";
4 |
5 | contract Admin {
6 | address public owner;
7 |
8 | constructor() public {
9 | owner = msg.sender;
10 | }
11 |
12 | modifier onlyOwner() {
13 | require(msg.sender == owner);
14 | _;
15 | }
16 |
17 | mapping(address => address) registeredEmployeesmap;
18 | mapping(address => address) registeredOrganizationmap;
19 | address[] registeredEmployees;
20 | address[] registeredOrganization;
21 |
22 | function registerUser(
23 | address EthAddress,
24 | string memory Name,
25 | string memory Location,
26 | string memory Description,
27 | uint256 Role
28 | ) public onlyOwner {
29 | if (Role == 1) {
30 | Employee newEmployee = new Employee(
31 | owner,
32 | EthAddress,
33 | Name,
34 | Location,
35 | Description
36 | );
37 | registeredEmployeesmap[EthAddress] = address(newEmployee);
38 | registeredEmployees.push(EthAddress);
39 | } else {
40 | OrganizationEndorser newOrganizationEndorser = new OrganizationEndorser(
41 | owner,
42 | EthAddress,
43 | Name,
44 | Location,
45 | Description
46 | );
47 | registeredOrganizationmap[EthAddress] = address(newOrganizationEndorser);
48 | registeredOrganization.push(EthAddress);
49 | }
50 | }
51 |
52 | /****************************************************************USER SECTION**************************************************/
53 |
54 | function isEmployee(address _employeeAddress) public view returns (bool) {
55 | return registeredEmployeesmap[_employeeAddress] != address(0x0);
56 | }
57 |
58 | function isOrganizationEndorser(address _organizationEndorser)
59 | public
60 | view
61 | returns (bool)
62 | {
63 | return registeredOrganizationmap[_organizationEndorser] != address(0x0);
64 | }
65 |
66 | function employeeCount() public view returns (uint256) {
67 | return registeredEmployees.length;
68 | }
69 |
70 | function getEmployeeContractByAddress(address _employee)
71 | public
72 | view
73 | returns (address)
74 | {
75 | return registeredEmployeesmap[_employee];
76 | }
77 |
78 | function getEmployeeContractByIndex(uint256 index)
79 | public
80 | view
81 | returns (address)
82 | {
83 | return getEmployeeContractByAddress(registeredEmployees[index]);
84 | }
85 |
86 | function OrganizationEndorserCount() public view returns (uint256) {
87 | return registeredOrganization.length;
88 | }
89 |
90 | function getOrganizationContractByAddress(address _organization)
91 | public
92 | view
93 | returns (address)
94 | {
95 | return registeredOrganizationmap[_organization];
96 | }
97 |
98 | function getOrganizationContractByIndex(uint256 index)
99 | public
100 | view
101 | returns (address)
102 | {
103 | return getOrganizationContractByAddress(registeredOrganization[index]);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/components/ScanQR.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from "react";
2 | import "./Modals.css";
3 | import QrReader from "react-qr-reader";
4 | import { Button, Header, Icon, Modal } from "semantic-ui-react";
5 |
6 | function ScanQR(props) {
7 | const qrRef = useRef(null);
8 | const [scanRes, setScanRes] = useState("");
9 | const [forward, setforward] = useState(false);
10 |
11 | const handleError = (err) => {
12 | console.log(err);
13 | };
14 |
15 | const handleScan = (res) => {
16 | if (res) {
17 | setScanRes(res);
18 | props.handleAddAddress(res);
19 | }
20 | };
21 |
22 | const onUploadQR = () => {
23 | qrRef.current.openImageDialog();
24 | };
25 |
26 | return (
27 |
28 | setforward(!forward)}
37 | />
38 |
44 | {!forward ? (
45 |
46 |
52 |
63 |
70 |
71 | Uploaded Address: {scanRes}
72 |
73 | ) : (
74 |
75 |
86 |
87 |
88 | Scanned Address: {scanRes}
89 |
90 | )}
91 |
92 | props?.closeScanQRModal()}
99 | />
100 |
101 |
102 | );
103 | }
104 |
105 | export default ScanQR;
106 |
--------------------------------------------------------------------------------
/src/components/SearchBar.js:
--------------------------------------------------------------------------------
1 | import _ from "lodash";
2 | import React, { Component } from "react";
3 | import { toast } from "react-toastify";
4 | import { Search } from "semantic-ui-react";
5 | import Skills from "../abis/Skills.json";
6 | import SearchEmp from "./SearchEmp";
7 | import "./Search.css";
8 |
9 | var source = [];
10 |
11 | const initialState = { isLoading: false, results: [], value: "" };
12 |
13 | export default class SearchBar extends Component {
14 | state = initialState;
15 |
16 | componentDidMount = async () => {
17 | const web3 = window.web3;
18 | const networkId = await web3.eth.net.getId();
19 | const skillData = await Skills.networks[networkId];
20 |
21 | if (skillData) {
22 | const skills = await new web3.eth.Contract(Skills.abi, skillData.address);
23 | const skillLength = await skills?.methods?.getSkillLength().call();
24 | const allSkills = await Promise.all(
25 | Array(parseInt(skillLength))
26 | .fill()
27 | .map((ele, index) => skills.methods?.getSkillsByIndex(index).call())
28 | );
29 |
30 | allSkills.forEach(async (skillname) => {
31 | const currSkillLen = await skills.methods
32 | ?.getTotalEmployeeInSkillByName(skillname)
33 | .call();
34 | const allEmp = await Promise.all(
35 | Array(parseInt(currSkillLen))
36 | .fill()
37 | .map((ele, index) =>
38 | skills.methods?.getEmployeeBySkillName(skillname, index).call()
39 | )
40 | );
41 | allEmp.forEach((emp, index) =>
42 | source.push({
43 | title: skillname,
44 | description: ,
45 | })
46 | );
47 | });
48 | } else {
49 | toast.error("Skill contract does not exist on this network!!");
50 | }
51 | };
52 |
53 | handleResultSelect = (e, { result }) =>
54 | this.setState({ value: result.title });
55 |
56 | handleSearchChange = (e, { value }) => {
57 | this.setState({ isLoading: true, value });
58 |
59 | setTimeout(() => {
60 | if (this.state.value.length < 1) return this.setState(initialState);
61 |
62 | const re = new RegExp(_.escapeRegExp(this.state.value), "i");
63 | const isMatch = (result) => re.test(result.title);
64 |
65 | this.setState({
66 | isLoading: false,
67 | results: _.filter(source, isMatch),
68 | });
69 | }, 300);
70 | };
71 |
72 | searchOptions = [
73 | { key: "1", text: "Employee", value: "1" },
74 | {
75 | key: "2",
76 | text: "Skill",
77 | value: "2",
78 | },
79 | ];
80 | render() {
81 | const { isLoading, value, results } = this.state;
82 | return (
83 | <>
84 |
99 | >
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/Organization.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Organization from "../../abis/OrganizationEndorser.json";
3 | import Admin from "../../abis/Admin.json";
4 | import { toast } from "react-toastify";
5 | import OrgEndCard from "../../components/OrgEndCard";
6 | import EmployeeCard from "../../components/EmployeeCard";
7 | import "./Organization.css";
8 | import GetEmployeeModal from "../../components/GetEmployeeModal";
9 | import LoadComp from "../../components/LoadComp";
10 |
11 | export default class OrganizationEndorser extends Component {
12 | state = {
13 | orgcontractAddress: "",
14 | employees: [],
15 | employeemodal: false,
16 | loadcomp: false,
17 | };
18 |
19 | componentDidMount = async () => {
20 | this.setState({ loadcomp: true });
21 | await this.getEmployees();
22 | this.setState({ loadcomp: false });
23 | };
24 |
25 | getEmployees = async () => {
26 | const web3 = window.web3;
27 | const networkId = await web3.eth.net.getId();
28 | const AdminData = await Admin.networks[networkId];
29 | const accounts = await web3.eth.getAccounts();
30 | if (AdminData) {
31 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
32 | const orgContractAddress = await admin?.methods
33 | ?.getOrganizationContractByAddress(accounts[0])
34 | .call();
35 | const orgContract = await new web3.eth.Contract(
36 | Organization.abi,
37 | orgContractAddress
38 | );
39 |
40 | const employeeCount = await orgContract?.methods?.totalEmployees().call();
41 |
42 | const employees = await Promise.all(
43 | Array(parseInt(employeeCount))
44 | .fill()
45 | .map(async (ele, index) => {
46 | const employee = await orgContract?.methods
47 | ?.getEmployeeByIndex(index)
48 | .call();
49 | return admin.methods.getEmployeeContractByAddress(employee).call();
50 | })
51 | );
52 | // console.log("emp", employees);
53 |
54 | this.setState({ orgContractAddress, employees });
55 | } else {
56 | toast.error("The Admin Contract does not exist on this network!");
57 | }
58 | };
59 |
60 | closeEmployeeModal = () => {
61 | this.setState({ employeemodal: false });
62 | this.getEmployees();
63 | };
64 |
65 | render() {
66 | return this.state.loadcomp ? (
67 |
68 | ) : (
69 |
70 |
74 | {this.state.orgContractAddress && (
75 |
76 | )}
77 |
78 |
79 |
82 |
85 | this.setState({
86 | employeemodal: !this.state.employeemodal,
87 | })
88 | }
89 | >
90 | Add Employee
91 |
92 |
Employees in the organization
93 |
94 |
95 | {this.state.employees?.map((employee, index) => (
96 |
97 | ))}
98 |
99 |
100 |
101 | );
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/components/GetSkillsModals.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import Employee from "../abis/Employee.json";
6 | import "./Modals.css";
7 |
8 | export default class GetSkillsModal extends Component {
9 | state = {
10 | name: "",
11 | experience: "",
12 | loading: false,
13 | };
14 |
15 | handleSubmit = async (e) => {
16 | this.setState({ loading: true });
17 | const { name, experience } = this.state;
18 | if (!name || !experience) {
19 | toast.error("Please enter all the fields.");
20 | return;
21 | }
22 | e.preventDefault();
23 | const web3 = window.web3;
24 | const networkId = await web3.eth.net.getId();
25 | const AdminData = await Admin.networks[networkId];
26 | const accounts = await web3.eth.getAccounts();
27 | if (AdminData) {
28 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
29 | const employeeContractAddress = await admin?.methods
30 | ?.getEmployeeContractByAddress(accounts[0])
31 | .call();
32 | const EmployeeContract = await new web3.eth.Contract(
33 | Employee.abi,
34 | employeeContractAddress
35 | );
36 | try {
37 | await EmployeeContract.methods.addSkill(name, experience).send({
38 | from: accounts[0],
39 | });
40 | toast.success("Skill saved successfully!!");
41 | } catch (err) {
42 | toast.error(err.message);
43 | }
44 | } else {
45 | toast.error("The Admin Contract does not exist on this network!");
46 | }
47 | this.setState({ loading: false });
48 | this.props.closeCertificationModal();
49 | };
50 |
51 | handleChange = (e) => {
52 | e.preventDefault();
53 | this.setState({ [e.target.id]: e.target.value });
54 | };
55 |
56 | render() {
57 | return (
58 | this.handleSubmit(e)}
61 | open={this.props.isOpen}
62 | size="tiny"
63 | className="modal-des"
64 | >
65 |
71 |
72 |
74 |
82 |
83 |
84 |
92 |
93 |
94 |
95 |
96 | this.props.closeCertificationModal()}
103 | />
104 |
112 |
113 |
114 | );
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/pages/Admin/Admin.css:
--------------------------------------------------------------------------------
1 | .create-user {
2 | position: fixed;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | -webkit-transform: translate(-50%, -50%);
7 | -moz-transform: translate(-50%, -50%);
8 | -o-transform: translate(-50%, -50%);
9 | -ms-transform: translate(-50%, -50%);
10 | margin-top: 40px;
11 | }
12 |
13 | .card-style {
14 | background: #1e2022ea !important;
15 | border-radius: 7px !important;
16 | color: #c5c6c7 !important;
17 | min-width: 360px;
18 | border: 1px solid white !important;
19 | box-shadow: 0px 0px 2px 0px white !important;
20 | }
21 |
22 | .card-heading {
23 | font-family: "Arvo", serif !important;
24 | color: white;
25 | font-size: 2rem;
26 | font-weight: 500;
27 | width: 100%;
28 | text-align: center;
29 | }
30 |
31 | .horizontal-line {
32 | border: none;
33 | border-top: 2px solid white;
34 | }
35 |
36 | .form-inputs-admin > input {
37 | border-radius: 7px !important;
38 | background: #1e2022ea !important;
39 | border: 1px solid white !important;
40 | box-shadow: 0px 0px 1px 0px white !important;
41 | color: white !important;
42 | }
43 |
44 | .form-inputs-admin > input::placeholder {
45 | color: white !important;
46 | opacity: 0.7;
47 | }
48 |
49 | .form-inputs-admin > input::selection {
50 | color: white !important;
51 | }
52 |
53 | .form-inputs-admin > input:focus {
54 | box-shadow: 0px 0px 2px 0px white !important;
55 | }
56 |
57 | .ui.selection.dropdown {
58 | border-radius: 7px !important;
59 | background: #1e2022ea !important;
60 | border: 1px solid white !important;
61 | box-shadow: 0px 0px 1px 0px white !important;
62 | color: white !important;
63 | }
64 |
65 | .ui.default.dropdown:not(.button) > .text,
66 | .ui.dropdown:not(.button) > .default.text {
67 | color: white !important;
68 | }
69 |
70 | .ui.selection.active.dropdown .menu {
71 | background: #1e2022ea !important;
72 | color: white !important;
73 | border-bottom-left-radius: 7px !important;
74 | border-bottom-right-radius: 7px !important;
75 | box-shadow: 0px 0px 1px 0px white !important;
76 | }
77 |
78 | .ui.selection.dropdown .menu > .item {
79 | color: white !important;
80 | border-top: 1px solid white !important;
81 | }
82 |
83 | .ui.dropdown .menu .selected.item,
84 | .ui.dropdown.selected {
85 | color: #1e2022ea !important;
86 | background: white !important;
87 | }
88 |
89 | .ui.selection.visible.dropdown > .text:not(.default) {
90 | color: white !important;
91 | }
92 |
93 | .button-holder {
94 | text-align: center;
95 | }
96 |
97 | .button-css-admin {
98 | border-radius: 10px !important;
99 | color: white !important;
100 | background: #1e2022ea !important;
101 | border: 2px solid white !important;
102 | box-shadow: 0px 0px 2px 0px white !important;
103 | text-align: center;
104 | }
105 |
106 | .button-css-admin:hover {
107 | background: white !important;
108 | color: #1e2022ea !important;
109 | }
110 |
111 | .sidechat-container {
112 | margin-top: 2rem;
113 | margin-left: 1rem;
114 | }
115 |
116 | .notifications {
117 | background: rgba(31, 30, 30, 0.581);
118 | width: 85%;
119 | margin-left: auto;
120 | margin-right: auto;
121 | height: 80vh;
122 | margin-top: 40px;
123 | border-radius: 10px;
124 | border: 1px solid white;
125 | box-shadow: inset 0 0 3px 0 white;
126 | }
127 |
128 | .sidechat-body {
129 | overflow: auto !important;
130 | }
131 |
132 | .notification-sidechat {
133 | color: white !important;
134 | }
135 |
136 | .notification-sidechat-subheading {
137 | color: #c5c6c7 !important;
138 | }
139 |
140 | .header-row > th {
141 | border-bottom: 1px solid white !important;
142 | }
143 |
144 | .row-cell-container {
145 | cursor: pointer;
146 | }
147 |
148 | .header-row-cell {
149 | border-bottom: 1px solid #c5c6c7 !important;
150 | }
151 |
152 | .row-cell-container :hover {
153 | transform: scale(1.01, 1.01);
154 | background: rgba(31, 30, 30, 0.1);
155 | }
156 |
--------------------------------------------------------------------------------
/src/components/SkillCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Card, CardContent } from "semantic-ui-react";
3 | import Employee from "../abis/Employee.json";
4 | import Admin from "../abis/Admin.json";
5 | import { buildStyles, CircularProgressbar } from "react-circular-progressbar";
6 | import { toast } from "react-toastify";
7 | import "./SkillCard.css";
8 |
9 | export default class SkillCard extends Component {
10 | state = {
11 | colour: ["#b6e498", "#61dafb", "#764abc", "#83cd29", "#00d1b2"],
12 | };
13 |
14 | removeSkill = async (name) => {
15 | const web3 = window.web3;
16 | const networkId = await web3.eth.net.getId();
17 | const AdminData = await Admin.networks[networkId];
18 | const accounts = await web3.eth.getAccounts();
19 | if (AdminData) {
20 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
21 | const employeeContractAddress = await admin?.methods
22 | ?.getEmployeeContractByAddress(accounts[0])
23 | .call();
24 | const EmployeeContract = await new web3.eth.Contract(
25 | Employee.abi,
26 | employeeContractAddress
27 | );
28 | await EmployeeContract?.methods
29 | ?.deleteSkill(name)
30 | .send({ from: accounts[0] });
31 | toast.success("Skill deleted successfully!!");
32 | window.location.reload(false);
33 | } else {
34 | toast.error("The Admin Contract does not exist on this network!");
35 | }
36 | };
37 |
38 | render() {
39 | const skill = this.props.skill;
40 | return (
41 |
42 | {this.props.update && (
43 | this.removeSkill(skill.name)}
46 | >
47 | {!skill.visible ? (
48 |
49 | ) : (
50 |
51 | )}
52 |
53 | )}
54 |
55 |
56 |
57 |
58 | {skill.name}
59 |
60 | {skill.experience}
61 |
62 |
63 |
64 | {skill.endorsed ? (
65 |
66 |
67 |
Endorsed By:
68 |
69 |
72 | {skill.endorser_address}
73 |
74 |
75 |
76 |
77 |
78 |
Review:
79 |
80 | {skill.review}
81 |
82 |
83 |
84 | ) : (
85 |
86 |
Not Yet Endorsed
87 |
88 | )}
89 |
90 |
110 |
111 |
112 |
113 | );
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/components/GetEmployeeModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Input, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import OrgEnd from "../abis/OrganizationEndorser.json";
6 | import "./Modals.css";
7 | import ScanQR from "./ScanQR";
8 |
9 | export default class GetEmployeeModal extends Component {
10 | state = {
11 | employee_address: "",
12 | loading: false,
13 | scanQR: false,
14 | };
15 | handleSubmit = async (e) => {
16 | const { employee_address } = this.state;
17 | if (!employee_address) {
18 | toast.error("Please enter all the fields.");
19 | return;
20 | }
21 | this.setState({ loading: true });
22 | e.preventDefault();
23 | const web3 = window.web3;
24 | const networkId = await web3.eth.net.getId();
25 | const AdminData = await Admin.networks[networkId];
26 | const accounts = await web3.eth.getAccounts();
27 | if (AdminData) {
28 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
29 | const orgContractAddress = await admin?.methods
30 | ?.getOrganizationContractByAddress(accounts[0])
31 | .call();
32 | const orgContract = await new web3.eth.Contract(
33 | OrgEnd.abi,
34 | orgContractAddress
35 | );
36 | try {
37 | await orgContract.methods.addEmployees(employee_address).send({
38 | from: accounts[0],
39 | });
40 | toast.success("Employee Added Successfully!!");
41 | } catch (err) {
42 | toast.error(err.message);
43 | }
44 | } else {
45 | toast.error("The Admin Contract does not exist on this network!");
46 | }
47 | this.setState({ loading: false });
48 | this.props.closeEmployeeModal();
49 | };
50 |
51 | handleChange = (e) => {
52 | e.preventDefault();
53 | this.setState({ [e.target.id]: e.target.value });
54 | };
55 |
56 | closeScanQRModal = () => {
57 | this.setState({ scanQR: false });
58 | };
59 |
60 | handleAddAddress = (res) => {
61 | this.setState({ employee_address: res });
62 | };
63 |
64 | render() {
65 | return (
66 | <>
67 |
72 | this.handleSubmit(e)}
75 | open={this.props.isOpen}
76 | size="tiny"
77 | className="modal-des"
78 | >
79 |
85 |
86 |
88 |
89 |
97 | this.setState({ scanQR: true })}
102 | />
103 |
104 |
105 |
106 |
107 |
108 | this.props.closeEmployeeModal()}
115 | />
116 |
124 |
125 |
126 | >
127 | );
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/components/GetEditFieldModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import Employee from "../abis/Employee.json";
6 | import "./Modals.css";
7 |
8 | export default class GetEditFieldModal extends Component {
9 | state = {
10 | name1: "",
11 | description1: "",
12 | location1: "",
13 | loading: false,
14 | };
15 |
16 | handleSubmit = async (e) => {
17 | var name = this.state.name1;
18 | var description = this.state.description1;
19 | var location = this.state.location1;
20 | if (!name) name = this.props.name;
21 | if (!location) location = this.props.location;
22 | if (!description) description = this.props.description;
23 | if (!name || !description || !location) {
24 | toast.error("Please enter all the fields.");
25 | return;
26 | }
27 | this.setState({ loading: true });
28 | e.preventDefault();
29 | const web3 = window.web3;
30 | const networkId = await web3.eth.net.getId();
31 | const AdminData = await Admin.networks[networkId];
32 | const accounts = await web3.eth.getAccounts();
33 | if (AdminData) {
34 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
35 | const employeeContractAddress = await admin?.methods
36 | ?.getEmployeeContractByAddress(accounts[0])
37 | .call();
38 | const EmployeeContract = await new web3.eth.Contract(
39 | Employee.abi,
40 | employeeContractAddress
41 | );
42 | try {
43 | await EmployeeContract.methods
44 | .editInfo(name, location, description)
45 | .send({
46 | from: accounts[0],
47 | });
48 | toast.success("Employee Info Updated");
49 | } catch (err) {
50 | toast.error(err.message);
51 | }
52 | } else {
53 | toast.error("The Admin Contract does not exist on this network!");
54 | }
55 | this.setState({ loading: false });
56 | this.props.closeEditFieldModal();
57 | };
58 |
59 | handleChange = (e) => {
60 | e.preventDefault();
61 | this.setState({ [e.target.id]: e.target.value });
62 | };
63 |
64 | render() {
65 | return (
66 | this.handleSubmit(e)}
69 | open={this.props.isOpen}
70 | size="tiny"
71 | className="modal-des"
72 | >
73 |
79 |
80 |
85 |
93 |
94 |
95 |
103 | {" "}
104 | >
105 | )}
106 | {this.props.isDescription && (
107 |
108 |
116 |
117 | )}
118 |
119 |
120 |
121 | this.props.closeEditFieldModal()}
128 | />
129 |
137 |
138 |
139 | );
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/pages/NoRole/Notifications.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Table, Header, Image, Grid } from "semantic-ui-react";
3 | import ChatBody from "../../components/ChatBody";
4 | import Nochats from "../../components/NoChats";
5 | import "./Notifications.css";
6 | import { db } from "../../firebase/firebase";
7 |
8 | export default class Notifications extends Component {
9 | colour = ["b6e498", "61dafb", "764abc", "83cd29", "00d1b2"];
10 | state = {
11 | curr: {},
12 | conversations: [],
13 | };
14 |
15 | componentDidMount = async () => {
16 | const web3 = window.web3;
17 | const accounts = await web3.eth.getAccounts();
18 | await db
19 | .collection("users")
20 | .doc(accounts[0])
21 | .collection("activechats")
22 | .onSnapshot((snapshot) =>
23 | this.setState({ conversations: snapshot.docs.map((doc) => doc.data()) })
24 | );
25 | console.log(this.state.conversations);
26 | };
27 |
28 | genImg = (name) => {
29 | return `https://ui-avatars.com/api/?background=${
30 | this.colour[Math.floor(Math.random() * 5)]
31 | }&color=fff&name=${name}`;
32 | };
33 |
34 | setCurr = (data) => {
35 | const curr = {
36 | ...data,
37 | avatar: this.genImg(data.name),
38 | };
39 | this.setState({ curr });
40 | };
41 |
42 | render() {
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Coversations
54 |
55 |
56 |
57 |
65 |
66 | {this.state?.conversations?.map((data) => {
67 | return (
68 | this.setCurr(data)}
71 | key={data.ethAddress}
72 | >
73 |
74 |
79 |
84 |
85 | {data.name}
86 |
87 |
93 | {data.ethAddress}
94 |
95 |
96 |
97 |
98 |
99 |
100 | );
101 | })}
102 |
103 |
104 |
105 |
106 |
107 |
108 | {this.state.curr.ethAddress ? (
109 |
115 | ) : (
116 |
117 | )}
118 |
119 |
120 |
121 |
122 | );
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/pages/Admin/Notifications.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Table, Header, Image, Grid } from "semantic-ui-react";
3 | import ChatBody from "../../components/ChatBody";
4 | import Nochats from "../../components/NoChats";
5 | import "./Admin.css";
6 | import { db } from "../../firebase/firebase";
7 |
8 | export default class NotificationsAdmin extends Component {
9 | colour = ["b6e498", "61dafb", "764abc", "83cd29", "00d1b2"];
10 | state = {
11 | curr: {},
12 | conversations: [],
13 | };
14 |
15 | componentDidMount = async () => {
16 | const web3 = window.web3;
17 | const accounts = await web3.eth.getAccounts();
18 | await db
19 | .collection("users")
20 | .doc(accounts[0])
21 | .collection("activechats")
22 | .onSnapshot((snapshot) =>
23 | this.setState({ conversations: snapshot.docs.map((doc) => doc.data()) })
24 | );
25 | console.log(this.state.conversations);
26 | };
27 |
28 | genImg = (name) => {
29 | return `https://ui-avatars.com/api/?background=${
30 | this.colour[Math.floor(Math.random() * 5)]
31 | }&color=fff&name=${name}`;
32 | };
33 |
34 | setCurr = (data) => {
35 | const curr = {
36 | ...data,
37 | avatar: this.genImg(data.name),
38 | };
39 | this.setState({ curr });
40 | };
41 |
42 | render() {
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Coversations
54 |
55 |
56 |
57 |
65 |
66 | {this.state?.conversations?.map((data) => {
67 | return (
68 | this.setCurr(data)}
71 | key={data.ethAddress}
72 | >
73 |
74 |
79 |
84 |
85 | {data.name}
86 |
87 |
93 | {data.ethAddress}
94 |
95 |
96 |
97 |
98 |
99 |
100 | );
101 | })}
102 |
103 |
104 |
105 |
106 |
107 |
108 | {this.state.curr.ethAddress ? (
109 |
116 | ) : (
117 |
118 | )}
119 |
120 |
121 |
122 |
123 | );
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/pages/NoRole/NoRole.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Button, Card, Dropdown, Form, Message } from "semantic-ui-react";
4 | import "./NoRole.css";
5 | import { messageAdmin } from "../../firebase/api.js";
6 |
7 | class NoRole extends Component {
8 | state = {
9 | name: "",
10 | location: "",
11 | description: "",
12 | role: 0,
13 | loading: false,
14 | errorMessage: "",
15 | message: "",
16 | };
17 |
18 | roleOptions = [
19 | {
20 | key: "0",
21 | text: "No-Role-Selected",
22 | value: "0",
23 | },
24 | {
25 | key: "1",
26 | text: "Employee",
27 | value: "1",
28 | },
29 | {
30 | key: "2",
31 | text: "OrganizationEndorser",
32 | value: "2",
33 | },
34 | ];
35 |
36 | handleDropdownSelect = (e, data) => {
37 | this.setState({ role: data.value });
38 | };
39 |
40 | handleChange = (e) => {
41 | e.preventDefault();
42 | this.setState({
43 | [e.target.id]: e.target.value,
44 | });
45 | };
46 |
47 | handleSubmit = async (e) => {
48 | e.preventDefault();
49 | this.setState({ loading: true });
50 | const info = {
51 | name: this.state.name,
52 | description: this.state.description,
53 | role: this.state.role,
54 | location: this.state.location,
55 | };
56 | await messageAdmin(info, this.state.message);
57 | this.setState({
58 | name: "",
59 | description: "",
60 | role: "0",
61 | location: "",
62 | message: "",
63 | loading: false,
64 | });
65 | };
66 |
67 | render() {
68 | return (
69 |
157 | );
158 | }
159 | }
160 |
161 | export default withRouter(NoRole);
162 |
--------------------------------------------------------------------------------
/src/components/GetCertificationModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Input, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import Employee from "../abis/Employee.json";
6 | import "./Modals.css";
7 | import ScanQR from "./ScanQR";
8 |
9 | export default class GetCertificationModal extends Component {
10 | state = {
11 | name: "",
12 | organization: "",
13 | score: "",
14 | loading: false,
15 | scanQR: false,
16 | };
17 |
18 | handleSubmit = async (e) => {
19 | const { name, organization, score } = this.state;
20 | if (!name || !organization || !(score >= 1 && score <= 100)) {
21 | toast.error("Please enter all the fields.");
22 | return;
23 | }
24 | this.setState({ loading: true });
25 | e.preventDefault();
26 | const web3 = window.web3;
27 | const networkId = await web3.eth.net.getId();
28 | const AdminData = await Admin.networks[networkId];
29 | const accounts = await web3.eth.getAccounts();
30 | if (AdminData) {
31 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
32 | const employeeContractAddress = await admin?.methods
33 | ?.getEmployeeContractByAddress(accounts[0])
34 | .call();
35 | const EmployeeContract = await new web3.eth.Contract(
36 | Employee.abi,
37 | employeeContractAddress
38 | );
39 | try {
40 | await EmployeeContract.methods
41 | .addCertification(name, organization, score)
42 | .send({
43 | from: accounts[0],
44 | });
45 | toast.success("Certification saved successfullyy!!");
46 | } catch (err) {
47 | toast.error(err.message);
48 | }
49 | } else {
50 | toast.error("The Admin Contract does not exist on this network!");
51 | }
52 | this.setState({ loading: false });
53 | this.props.closeCertificationModal();
54 | };
55 |
56 | handleChange = (e) => {
57 | e.preventDefault();
58 | this.setState({ [e.target.id]: e.target.value });
59 | };
60 |
61 | closeScanQRModal = () => {
62 | this.setState({ scanQR: false });
63 | };
64 |
65 | handleAddAddress = (res) => {
66 | this.setState({ organization: res });
67 | };
68 |
69 | render() {
70 | return (
71 | <>
72 |
77 | this.handleSubmit(e)}
80 | open={this.props.isOpen}
81 | size="tiny"
82 | className="modal-des"
83 | >
84 |
90 |
91 |
93 |
101 |
102 |
103 |
104 |
112 | this.setState({ scanQR: true })}
117 | />
118 |
119 |
120 |
121 |
132 |
133 |
134 |
135 |
136 | this.props.closeCertificationModal()}
143 | />
144 |
152 |
153 |
154 | >
155 | );
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/pages/Employee/Notifications.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Table, Header, Image, Grid } from "semantic-ui-react";
3 | import ChatBody from "../../components/ChatBody";
4 | import Nochats from "../../components/NoChats";
5 | import "./UpdateProfile.css";
6 | import { db } from "../../firebase/firebase";
7 | import Admin from "../../abis/Admin.json";
8 | import { toast } from "react-toastify";
9 |
10 | export default class NotificationsEmployee extends Component {
11 | colour = ["b6e498", "61dafb", "764abc", "83cd29", "00d1b2"];
12 | state = {
13 | curr: {},
14 | conversations: [],
15 | admin: "",
16 | };
17 |
18 | componentDidMount = async () => {
19 | const web3 = window.web3;
20 | const accounts = await web3.eth.getAccounts();
21 | await db
22 | .collection("users")
23 | .doc(accounts[0])
24 | .collection("activechats")
25 | .onSnapshot((snapshot) =>
26 | this.setState({ conversations: snapshot.docs.map((doc) => doc.data()) })
27 | );
28 | const networkId = await web3.eth.net.getId();
29 | const AdminData = await Admin.networks[networkId];
30 | if (AdminData) {
31 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
32 | const owner = await admin?.methods?.owner().call();
33 | this.setState({
34 | admin: owner,
35 | });
36 | } else {
37 | toast.error("The Admin Contract does not exist on this network!");
38 | }
39 | };
40 |
41 | genImg = (name) => {
42 | return `https://ui-avatars.com/api/?background=${
43 | this.colour[Math.floor(Math.random() * 5)]
44 | }&color=fff&name=${name}`;
45 | };
46 |
47 | setCurr = (data) => {
48 | const curr = {
49 | ...data,
50 | avatar: this.genImg(data.name),
51 | };
52 | this.setState({ curr });
53 | };
54 |
55 | render() {
56 | return (
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | Coversations
67 |
68 |
69 |
70 |
78 |
79 | {this.state?.conversations?.map((data) => {
80 | return (
81 | this.setCurr(data)}
84 | key={data.ethAddress}
85 | >
86 |
87 |
92 |
97 |
98 | {data.name}
99 |
100 |
106 | {data.ethAddress}
107 |
108 |
109 |
110 |
111 |
112 |
113 | );
114 | })}
115 |
116 |
117 |
118 |
119 |
120 |
121 | {this.state.curr.ethAddress ? (
122 |
131 | ) : (
132 |
133 | )}
134 |
135 |
136 |
137 |
138 | );
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/Notifications.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Table, Header, Image, Grid } from "semantic-ui-react";
3 | import ChatBody from "../../components/ChatBody";
4 | import Nochats from "../../components/NoChats";
5 | import "./Organization.css";
6 | import { db } from "../../firebase/firebase";
7 | import Admin from "../../abis/Admin.json";
8 | import { toast } from "react-toastify";
9 |
10 | export default class NotificationsOrg extends Component {
11 | colour = ["b6e498", "61dafb", "764abc", "83cd29", "00d1b2"];
12 | state = {
13 | curr: {},
14 | conversations: [],
15 | admin: "",
16 | };
17 |
18 | componentDidMount = async () => {
19 | const web3 = window.web3;
20 | const accounts = await web3.eth.getAccounts();
21 | await db
22 | .collection("users")
23 | .doc(accounts[0])
24 | .collection("activechats")
25 | .onSnapshot((snapshot) =>
26 | this.setState({ conversations: snapshot.docs.map((doc) => doc.data()) })
27 | );
28 | const networkId = await web3.eth.net.getId();
29 | const AdminData = await Admin.networks[networkId];
30 | if (AdminData) {
31 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
32 | const owner = await admin?.methods?.owner().call();
33 | this.setState({
34 | admin: owner,
35 | });
36 | } else {
37 | toast.error("The Admin Contract does not exist on this network!");
38 | }
39 | };
40 |
41 | genImg = (name) => {
42 | return `https://ui-avatars.com/api/?background=${
43 | this.colour[Math.floor(Math.random() * 5)]
44 | }&color=fff&name=${name}`;
45 | };
46 |
47 | setCurr = (data) => {
48 | const curr = {
49 | ...data,
50 | avatar: this.genImg(data.name),
51 | };
52 | this.setState({ curr });
53 | };
54 |
55 | render() {
56 | return (
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | Coversations
67 |
68 |
69 |
70 |
78 |
79 | {this.state?.conversations?.map((data) => {
80 | return (
81 | this.setCurr(data)}
84 | key={data.ethAddress}
85 | >
86 |
87 |
92 |
97 |
98 | {data.name}
99 |
100 |
106 | {data.ethAddress}
107 |
108 |
109 |
110 |
111 |
112 |
113 | );
114 | })}
115 |
116 |
117 |
118 |
119 |
120 |
121 | {this.state.curr.ethAddress ? (
122 |
132 | ) : (
133 |
134 | )}
135 |
136 |
137 |
138 |
139 | );
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Skillset Verified
2 |
3 | A blockchain-based skill verification system can help reduce the time spent on conducting competency checks, skill verification and build more trust in the skill and competency management within the organisation. With Blockchain, an employee can have his/her skills recorded on an available network which are also verified and approved by their previous managers/employers. Thus with a skill chain based on the blockchain for an employee, we can be completely assured of the skills, experience, learning goal progress and their competency level along with a transparency of who have endorsed the employees on these skills. Further, this will help organisation to help optimally leverage credible employees for respective business needs.
4 |
5 | ### Deployments
6 |
7 | - **Video Demo** - https://vimeo.com/629030779/cb18ff23a5
8 | - **Flowchart** - https://whimsical.com/frontend-PkzGdD585qXChFvYVDebCh
9 | - **Deployed URL** - https://kind-grass-06d9d2100.azurestaticapps.net/
10 |
11 | ### Use cases
12 |
13 | 1. Can be used by the HR for smooth hiring process.
14 | 2. Can be used by the employee to get into the company of his dreams.
15 | 3. Can be used to do competency checks.
16 | 4. Can be used to chat with organizations & employees.
17 |
18 | ## Features
19 |
20 | - The Website has a _**search feature**_ for both employee and HR for searching perticular person for Job requirement matches.
21 | - _**Notificaton**_ System to alert the employee for the scheduled interview.
22 | - Notification For Certifications and skill endorsements.
23 | - _**Charts and graphs**_ in the employee profile page to show the endorsement ratings, certifications time and date.
24 | - _**Barcode scanner**_ to scan the the barcode generated from the public key hash of the employee and organization to make connecting more easy.
25 | - In App _**chat feature**_ to allow employees and HR connect with each other.Employees can request for a endorsement for a skill,certification and experience and HR can connect with employee for a interview.
26 | - Chats are _**end to end encrpted**_ using public-private key cryptography.
27 | - Login is being handled by your metamask account so there is no requirement for the signup/signin.
28 |
29 | ### Brief Flow Diagram
30 | 
31 |
32 | ---
33 |
34 | ## Roles
35 |
36 | 1. **No Role**
37 | - A user having a ethereum account can send he admins his/her profile and cha with them as well.
38 | - He can request for any role employee or organization.
39 |
40 |
41 | 2. **Admin**
42 | - Registers a new user on the blockchain.
43 | - Controls any ambiguity in the blockchain.
44 | - Responds to role requests from users.
45 | - Maintains and scale users.
46 | - Can revove/reassign roles of users.
47 |
48 |
49 | 3. **Employees**
50 | - This smart contract is for the employee, It will be storing data regarding the employee:
51 | - Employee Name, overall endorsement Rating, each skill listed along with its endorsement rating(scale 1-10).
52 | - Certifications - There will be 2 types of certifications verified and not verified. A certification is considered verified when the organization providing the certificate approves it on the blockchain.
53 | - Work Experiences - It will contain the fields like (Organization name, Job Title, Description etc.) it will be of two types verified and not. It is considered verified if the organization approves it on blockchain.
54 | - Platform Ratings (Like Hackerearth, Codechef, Codeforces etc.) .These Ratings will be verified via a API call to the server of given platforms and the exact ratings will be displayed on the page so there is no need to click on a bunch of links to verify.
55 | - Education Verification - These details are crosschecked with the transcript provided by the employee (or if the university/college provides a API domain to recheck the results it will be implemented) which is then stored in the blockchain.
56 |
57 |
58 |
59 | 4. **Organization Endorser**
60 | - This smart contract is for the organizations. It can be used by the organizations to verify the skillset, work experience, education, certifications of their employees.The smart contracts contains:
61 | - Organization Name.
62 | - It contains a mapping of the current employees of this organization, and these employees are certified to endorse a skill, work experience and education of another employee. Only the current employees are authorized to do so not the past employees.
63 | - It contains a list of all the HRs, Talent aquisition team and all the employees working in the organization.
64 | - It will be having a feature to update job title of a employee.
65 | - It will have a feature to grant a certificate to an employee for their achivements and it will be displayed on their profiles.
66 | - It will have a feature to search employees on the blockchain according to the job description and invite them for an interview.
67 |
68 | ## Thumbnails
69 | 
70 | 
71 | 
72 | 
73 | 
74 | 
75 | 
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/components/GetEducationModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Input, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import Employee from "../abis/Employee.json";
6 | import "./Modals.css";
7 | import ScanQR from "./ScanQR";
8 |
9 | export default class GetEducationModal extends Component {
10 | state = {
11 | institute: "",
12 | startdate: "",
13 | enddate: "",
14 | description: "",
15 | loading: false,
16 | scanQR: false,
17 | };
18 |
19 | handleSubmit = async (e) => {
20 | const { institute, startdate, enddate, description } = this.state;
21 | if (!institute || !startdate || !enddate || !description) {
22 | toast.error("Please enter all the fields.");
23 | return;
24 | }
25 | this.setState({ loading: true });
26 | e.preventDefault();
27 | const web3 = window.web3;
28 | const networkId = await web3.eth.net.getId();
29 | const AdminData = await Admin.networks[networkId];
30 | const accounts = await web3.eth.getAccounts();
31 | if (AdminData) {
32 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
33 | const employeeContractAddress = await admin?.methods
34 | ?.getEmployeeContractByAddress(accounts[0])
35 | .call();
36 | const EmployeeContract = await new web3.eth.Contract(
37 | Employee.abi,
38 | employeeContractAddress
39 | );
40 | try {
41 | await EmployeeContract.methods
42 | .addEducation(institute, startdate, enddate, description)
43 | .send({
44 | from: accounts[0],
45 | });
46 | toast.success("Education saved successfullyy!!");
47 | } catch (err) {
48 | toast.error(err.message);
49 | }
50 | } else {
51 | toast.error("The Admin Contract does not exist on this network!");
52 | }
53 | this.setState({ loading: false });
54 | this.props.closeCertificationModal();
55 | };
56 |
57 | handleChange = (e) => {
58 | e.preventDefault();
59 | this.setState({ [e.target.id]: e.target.value });
60 | };
61 |
62 | closeScanQRModal = () => {
63 | this.setState({ scanQR: false });
64 | };
65 |
66 | handleAddAddress = (res) => {
67 | this.setState({ institute: res });
68 | };
69 |
70 | render() {
71 | return (
72 | <>
73 |
78 | this.handleSubmit(e)}
81 | open={this.props.isOpen}
82 | size="tiny"
83 | className="modal-des"
84 | >
85 |
91 |
92 |
94 |
95 |
103 | this.setState({ scanQR: true })}
108 | />
109 |
110 |
111 |
112 |
120 |
121 |
122 |
130 |
131 |
132 |
140 |
141 |
142 |
143 |
144 | this.props.closeCertificationModal()}
151 | />
152 |
160 |
161 |
162 | >
163 | );
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { toast, ToastContainer } from "react-toastify";
3 | import Web3 from "web3";
4 | import Admin from "./abis/Admin.json";
5 | import "react-toastify/dist/ReactToastify.css";
6 | import MetaMaskGuide from "./MetaMaskGuide";
7 | import { Container } from "semantic-ui-react";
8 | import { BrowserRouter, Route, Switch } from "react-router-dom";
9 | import AdminPageCreate from "./pages/Admin/CreateUser";
10 | import AllEmployees from "./pages/Admin/AllEmployees";
11 | import AllOrganizationEndorser from "./pages/Admin/AllOrganizationEndorser";
12 | import EmployeePage from "./pages/Employee/Employee";
13 | import UpdateProfile from "./pages/Employee/UpdateProfile";
14 | import Organization from "./pages/OrganizationEndorser/Organization";
15 | import EndorseSkill from "./pages/OrganizationEndorser/EndorseSkill";
16 | import Endorse from "./pages/OrganizationEndorser/EndorseSection";
17 | import Navbar from "./components/Navbar";
18 | import GetEmployee from "./pages/GetRoutes/GetEmployee";
19 | import GetOrg from "./pages/GetRoutes/GetOrg";
20 | import NoRole from "./pages/NoRole/NoRole";
21 | import Notifications from "./pages/NoRole/Notifications";
22 | import NotificationsAdmin from "./pages/Admin/Notifications";
23 | import NotificationsEmployee from "./pages/Employee/Notifications";
24 | import NotificationsOrg from "./pages/OrganizationEndorser/Notifications";
25 | import LoadComp from "./components/LoadComp";
26 |
27 | function App() {
28 | const [isMeta, setisMeta] = useState(false);
29 | const [isEmployee, setisEmployee] = useState(false);
30 | const [account, setaccount] = useState("");
31 | const [isOrganizationEndorser, setisOrganizationEndorser] = useState(false);
32 | const [isOwner, setisOwner] = useState(false);
33 | const [loadcomp, setloadcomp] = useState(false);
34 |
35 | const loadBlockChainData = async () => {
36 | const web3 = window.web3;
37 | const accounts = await web3.eth.getAccounts();
38 | if (accounts) {
39 | setaccount(accounts[0]);
40 | }
41 | const networkId = await web3.eth.net.getId();
42 | const AdminData = await Admin.networks[networkId];
43 | if (AdminData) {
44 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
45 | const isEmployee = await admin?.methods?.isEmployee(accounts[0]).call();
46 | const isOrganizationEndorser = await admin?.methods
47 | ?.isOrganizationEndorser(accounts[0])
48 | .call();
49 | const owner = await admin?.methods?.owner().call();
50 | setisEmployee(isEmployee);
51 | setisOrganizationEndorser(isOrganizationEndorser);
52 | setisOwner(owner === accounts[0]);
53 | } else {
54 | toast.error("The Admin Contract does not exist on this network!");
55 | }
56 | };
57 |
58 | useEffect(() => {
59 | const func = async () => {
60 | setisMeta(true);
61 | setloadcomp(true);
62 | if (window.ethereum) {
63 | await window.ethereum.request({
64 | method: "eth_requestAccounts",
65 | });
66 | window.web3 = await new Web3(window.ethereum);
67 | await loadBlockChainData();
68 | } else if (window.web3) {
69 | window.web3 = await new Web3(window.web3.currentProvider);
70 | await loadBlockChainData();
71 | } else {
72 | setisMeta(false);
73 | }
74 | setloadcomp(false);
75 | };
76 | func();
77 | return () => {
78 | //
79 | };
80 | }, []);
81 |
82 | const adminRoutes = () => {
83 | return (
84 |
85 |
86 |
91 |
92 |
93 |
94 | );
95 | };
96 |
97 | const employeeRoutes = () => {
98 | return (
99 |
100 |
101 |
102 |
103 |
104 | );
105 | };
106 |
107 | const isOrganizationEndorserRoutes = () => {
108 | return (
109 |
110 |
111 |
112 |
113 |
114 |
115 | );
116 | };
117 |
118 | const noRoleRoutes = () => {
119 | return (
120 |
121 |
122 |
123 |
124 | );
125 | };
126 |
127 | const renderRoutes = () => {
128 | if (isOwner) return adminRoutes();
129 | else if (isEmployee) return employeeRoutes();
130 | else if (isOrganizationEndorser) return isOrganizationEndorserRoutes();
131 | else return noRoleRoutes();
132 | };
133 |
134 | return (
135 |
136 | {loadcomp ? (
137 |
138 | ) : isMeta && account !== "" ? (
139 |
140 |
141 |
142 |
143 |
144 |
149 |
150 | {renderRoutes()}
151 |
152 |
153 |
154 | ) : (
155 |
156 | )}
157 |
158 | );
159 | }
160 |
161 | export default App;
162 |
--------------------------------------------------------------------------------
/src/components/GetWorkExpModal.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { toast } from "react-toastify";
3 | import { Button, Form, Header, Input, Modal } from "semantic-ui-react";
4 | import Admin from "../abis/Admin.json";
5 | import Employee from "../abis/Employee.json";
6 | import "./Modals.css";
7 | import ScanQR from "./ScanQR";
8 |
9 | export default class GetWorkExpModal extends Component {
10 | state = {
11 | role: "",
12 | organization: "",
13 | startdate: "",
14 | enddate: "",
15 | description: "",
16 | loading: false,
17 | scanQR: false,
18 | };
19 |
20 | handleSubmit = async (e) => {
21 | const { role, organization, startdate, enddate, description } = this.state;
22 | if (!role | !organization || !startdate || !enddate || !description) {
23 | toast.error("Please enter all the fields.");
24 | return;
25 | }
26 | this.setState({ loading: true });
27 | e.preventDefault();
28 | const web3 = window.web3;
29 | const networkId = await web3.eth.net.getId();
30 | const AdminData = await Admin.networks[networkId];
31 | const accounts = await web3.eth.getAccounts();
32 | if (AdminData) {
33 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
34 | const employeeContractAddress = await admin?.methods
35 | ?.getEmployeeContractByAddress(accounts[0])
36 | .call();
37 | const EmployeeContract = await new web3.eth.Contract(
38 | Employee.abi,
39 | employeeContractAddress
40 | );
41 | try {
42 | await EmployeeContract.methods
43 | .addWorkExp(role, organization, startdate, enddate, description)
44 | .send({
45 | from: accounts[0],
46 | });
47 | toast.success("Certification saved successfullyy!!");
48 | } catch (err) {
49 | toast.error(err.message);
50 | }
51 | } else {
52 | toast.error("The Admin Contract does not exist on this network!");
53 | }
54 | this.setState({ loading: false });
55 | this.props.closeCertificationModal();
56 | };
57 |
58 | handleChange = (e) => {
59 | e.preventDefault();
60 | this.setState({ [e.target.id]: e.target.value });
61 | };
62 |
63 | closeScanQRModal = () => {
64 | this.setState({ scanQR: false });
65 | };
66 |
67 | handleAddAddress = (res) => {
68 | this.setState({ organization: res });
69 | };
70 |
71 | render() {
72 | return (
73 | <>
74 |
79 | this.handleSubmit(e)}
82 | open={this.props.isOpen}
83 | size="tiny"
84 | className="modal-des"
85 | >
86 |
92 |
93 |
95 |
103 |
104 |
105 |
106 |
114 | this.setState({ scanQR: true })}
119 | />
120 |
121 |
122 |
123 |
131 |
132 |
133 |
141 |
142 |
143 |
151 |
152 |
153 |
154 |
155 | this.props.closeCertificationModal()}
162 | />
163 |
171 |
172 |
173 | >
174 | );
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/EndorseSkill.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Button, Card, Form, Input, Message } from "semantic-ui-react";
3 | import "./EndorsePage.css";
4 | import Admin from "../../abis/Admin.json";
5 | import Employee from "../../abis/Employee.json";
6 | import Skills from "../../abis/Skills.json";
7 | import { toast } from "react-toastify";
8 | import ScanQR from "../../components/ScanQR";
9 |
10 | export default class EndorseSkil extends Component {
11 | state = {
12 | employee_address_skill: "",
13 | skill_name: "",
14 | skill_score: "",
15 | skill_review: "",
16 | skillError: "",
17 | skillLoading: false,
18 | scanQR: false,
19 | };
20 |
21 | handleChange = (e) => {
22 | e.preventDefault();
23 | this.setState({ [e.target.id]: e.target.value });
24 | };
25 |
26 | handleSkillEndorse = async (e) => {
27 | e.preventDefault();
28 | this.setState({ skillLoading: true, skillError: "" });
29 | const { employee_address_skill, skill_name, skill_score, skill_review } =
30 | this.state;
31 | if (
32 | !employee_address_skill ||
33 | !skill_name ||
34 | !(skill_score >= 1 && skill_score <= 100) ||
35 | !skill_review
36 | ) {
37 | toast.error("Please enter all the fields.");
38 | return;
39 | }
40 | e.preventDefault();
41 | const web3 = window.web3;
42 | const networkId = await web3.eth.net.getId();
43 | const AdminData = await Admin.networks[networkId];
44 | const SkillData = await Skills.networks[networkId];
45 | const accounts = await web3.eth.getAccounts();
46 | if (AdminData && SkillData) {
47 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
48 | const skills = await new web3.eth.Contract(Skills.abi, SkillData.address);
49 | const employeeContractAddress = await admin?.methods
50 | ?.getEmployeeContractByAddress(employee_address_skill)
51 | .call();
52 | const EmployeeContract = await new web3.eth.Contract(
53 | Employee.abi,
54 | employeeContractAddress
55 | );
56 |
57 | try {
58 | await EmployeeContract.methods
59 | .endorseSkill(skill_name, skill_score, skill_review)
60 | .send({
61 | from: accounts[0],
62 | });
63 | await skills?.methods
64 | ?.addEmployeeToSkill(skill_name, employee_address_skill)
65 | .send({ from: accounts[0] });
66 | toast.success("Skill Endorsed successfully!!");
67 | } catch (err) {
68 | this.setState({ skillError: err.message });
69 | }
70 | } else {
71 | toast.error("The Admin Contract does not exist on this network!");
72 | }
73 | this.setState({
74 | skillLoading: false,
75 | skill_name: "",
76 | skill_review: "",
77 | skill_score: "",
78 | employee_address_skill: "",
79 | });
80 | };
81 |
82 | closeScanQRModal = () => {
83 | this.setState({ scanQR: false });
84 | };
85 |
86 | handleAddAddress = (res) => {
87 | this.setState({ employee_address_skill: res });
88 | };
89 |
90 | render() {
91 | return (
92 | <>
93 |
98 |
182 | >
183 | );
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/src/pages/OrganizationEndorser/EndorseSection.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import {
3 | Button,
4 | Card,
5 | Dropdown,
6 | Form,
7 | Input,
8 | Message,
9 | } from "semantic-ui-react";
10 | import "./EndorsePage.css";
11 | import Admin from "../../abis/Admin.json";
12 | import Employee from "../../abis/Employee.json";
13 | import { toast } from "react-toastify";
14 | import ScanQR from "../../components/ScanQR";
15 |
16 | export default class Endorse extends Component {
17 | state = {
18 | employee_address: "",
19 | section: "",
20 | skillLoading: false,
21 | certification_name: "",
22 | scanQR: false,
23 | };
24 |
25 | handleChange = (e) => {
26 | e.preventDefault();
27 | this.setState({ [e.target.id]: e.target.value });
28 | };
29 |
30 | handleSkillEndorse = async (e) => {
31 | e.preventDefault();
32 | this.setState({ skillLoading: true, skillError: "" });
33 | const { employee_address, section, certification_name } = this.state;
34 | if (!employee_address || !section) {
35 | toast.error("Please enter all the fields.");
36 | return;
37 | }
38 | if (section === "3" && !certification_name) {
39 | toast.error("Please enter all the fields.");
40 | return;
41 | }
42 | e.preventDefault();
43 | const web3 = window.web3;
44 | const networkId = await web3.eth.net.getId();
45 | const AdminData = await Admin.networks[networkId];
46 | const accounts = await web3.eth.getAccounts();
47 | if (AdminData) {
48 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
49 | const employeeContractAddress = await admin?.methods
50 | ?.getEmployeeContractByAddress(employee_address)
51 | .call();
52 | const EmployeeContract = await new web3.eth.Contract(
53 | Employee.abi,
54 | employeeContractAddress
55 | );
56 | // console.log(employeeContractAddress, EmployeeContract);
57 | try {
58 | if (section === 1) {
59 | await EmployeeContract?.methods
60 | ?.endorseEducation()
61 | .send({ from: accounts[0] });
62 | } else if (section === 2) {
63 | await EmployeeContract?.methods
64 | ?.endorseWorkExp()
65 | .send({ from: accounts[0] });
66 | } else {
67 | console.log(certification_name);
68 | await EmployeeContract?.methods
69 | ?.endorseCertification(certification_name)
70 | .send({ from: accounts[0] });
71 | }
72 | toast.success("Endorsed successfully!!");
73 | } catch (err) {
74 | this.setState({ skillError: err.message });
75 | }
76 | } else {
77 | toast.error("The Admin Contract does not exist on this network!");
78 | }
79 | this.setState({
80 | skillLoading: false,
81 | section: "",
82 | employee_address: "",
83 | });
84 | };
85 |
86 | closeScanQRModal = () => {
87 | this.setState({ scanQR: false });
88 | };
89 |
90 | handleAddAddress = (res) => {
91 | this.setState({ employee_address: res });
92 | };
93 |
94 | roleOptions = [
95 | {
96 | key: "0",
97 | text: "No-Role-Selected",
98 | value: "0",
99 | },
100 | {
101 | key: "1",
102 | text: "Endorse Education",
103 | value: "1",
104 | },
105 | {
106 | key: "2",
107 | text: "Endorse Work Experience",
108 | value: "2",
109 | },
110 | {
111 | key: "3",
112 | text: "Endorse Certification",
113 | value: "3",
114 | },
115 | ];
116 |
117 | handleDropdownSelect = (e, data) => {
118 | this.setState({ section: data.value });
119 | };
120 |
121 | render() {
122 | return (
123 | <>
124 |
129 |
201 | >
202 | );
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/pages/Admin/CreateUser.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { withRouter } from "react-router-dom";
3 | import {
4 | Button,
5 | Card,
6 | Dropdown,
7 | Form,
8 | Input,
9 | Message,
10 | } from "semantic-ui-react";
11 | import Admin from "../../abis/Admin.json";
12 | import { toast } from "react-toastify";
13 | import ScanQR from "../../components/ScanQR";
14 | import "./Admin.css";
15 |
16 | class CreateUser extends Component {
17 | state = {
18 | name: "",
19 | location: "",
20 | ethAddress: "",
21 | description: "",
22 | role: 0,
23 | loading: false,
24 | errorMessage: "",
25 | scanQR: false,
26 | };
27 |
28 | roleOptions = [
29 | {
30 | key: "0",
31 | text: "No-Role-Selected",
32 | value: "0",
33 | },
34 | {
35 | key: "1",
36 | text: "Employee",
37 | value: "1",
38 | },
39 | {
40 | key: "2",
41 | text: "OrganizationEndorser",
42 | value: "2",
43 | },
44 | ];
45 |
46 | handleDropdownSelect = (e, data) => {
47 | this.setState({ role: data.value });
48 | };
49 |
50 | handleChange = (e) => {
51 | e.preventDefault();
52 | this.setState({
53 | [e.target.id]: e.target.value,
54 | });
55 | };
56 |
57 | handleSubmit = async (e) => {
58 | e.preventDefault();
59 | const { ethAddress, name, location, role, description } = this.state;
60 | if (!name || !location || !description || !role || !ethAddress) {
61 | toast.error("Please fill all the fields!!");
62 | return;
63 | }
64 | this.setState({ loading: true, errorMessage: "" });
65 | const web3 = window.web3;
66 | const accounts = await web3.eth.getAccounts();
67 | const networkId = await web3.eth.net.getId();
68 | const AdminData = await Admin.networks[networkId];
69 | if (AdminData) {
70 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
71 |
72 | const owner = await admin.methods.owner().call();
73 | if (owner !== accounts[0]) {
74 | this.setState({
75 | errorMessage: "Sorry! You are not the Admin!!",
76 | loading: false,
77 | });
78 | return;
79 | }
80 | try {
81 | await admin.methods
82 | .registerUser(ethAddress, name, location, description, role)
83 | .send({ from: accounts[0] });
84 | toast.success("New user registered succressfully!!!!");
85 | this.props.history.push(
86 | `${role === "1" ? "/" : "/all-organization-endorser"}`
87 | );
88 | this.setState({
89 | name: "",
90 | location: "",
91 | ethAddress: "",
92 | description: "",
93 | role: 0,
94 | });
95 | } catch (err) {
96 | this.setState({ errorMessage: err.message });
97 | }
98 | this.setState({ loading: false });
99 | }
100 | };
101 |
102 | closeScanQRModal = () => {
103 | this.setState({ scanQR: false });
104 | };
105 |
106 | handleAddAddress = (res) => {
107 | this.setState({ ethAddress: res });
108 | };
109 |
110 | render() {
111 | return (
112 | <>
113 |
118 |
209 | >
210 | );
211 | }
212 | }
213 |
214 | export default withRouter(CreateUser);
215 |
--------------------------------------------------------------------------------
/src/firebase/api.js:
--------------------------------------------------------------------------------
1 | import { toast } from "react-toastify";
2 | import Admin from "../abis/Admin.json";
3 | import { db } from "./firebase";
4 |
5 | export const messageAdmin = async (info, message) => {
6 | const web3 = window.web3;
7 | const accounts = await web3.eth.getAccounts();
8 | const networkId = await web3.eth.net.getId();
9 | const AdminData = await Admin.networks[networkId];
10 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
11 | const owner = await admin.methods?.owner().call();
12 | var key = "";
13 | if (owner < accounts[0]) key = owner + "#" + accounts[0];
14 | else key = accounts[0] + "#" + owner;
15 | try {
16 | await db
17 | .collection("chats")
18 | .doc(key)
19 | .collection("chatmessages")
20 | .add({
21 | info: { ...info, ethAddress: accounts[0] },
22 | message: message,
23 | sender: accounts[0],
24 | receiver: owner,
25 | timeStamp: new Date(),
26 | });
27 |
28 | const doc = await db
29 | .collection("users")
30 | .doc(accounts[0])
31 | .collection("activechats")
32 | .doc(owner)
33 | .get();
34 | if (!doc.exists) {
35 | await db
36 | .collection("users")
37 | .doc(accounts[0])
38 | .collection("activechats")
39 | .doc(owner)
40 | .set({
41 | name: "Admin",
42 | ethAddress: owner,
43 | });
44 | await db
45 | .collection("users")
46 | .doc(owner)
47 | .collection("activechats")
48 | .doc(accounts[0])
49 | .set({
50 | name: info.name,
51 | ethAddress: accounts[0],
52 | });
53 | }
54 | toast.success("One of the admins will get back to you shortly!");
55 | } catch (err) {
56 | console.log(err);
57 | }
58 | };
59 |
60 | export const reqWorkexpEndorsementFunc = async (workexp) => {
61 | const { organization, role, startdate, enddate, description } = workexp;
62 | const web3 = window.web3;
63 | const accounts = await web3.eth.getAccounts();
64 | var key;
65 | if (organization < accounts[0]) {
66 | key = organization + "#" + accounts[0];
67 | } else {
68 | key = accounts[0] + "#" + organization;
69 | }
70 | try {
71 | await db
72 | .collection("chats")
73 | .doc(key)
74 | .collection("chatmessages")
75 | .add({
76 | info: {
77 | req: "Work Experience Endorsement Request",
78 | description,
79 | organization,
80 | startdate,
81 | enddate,
82 | role,
83 | ethAddress: accounts[0],
84 | },
85 | message: "Please endorse!!",
86 | sender: accounts[0],
87 | receiver: organization,
88 | timeStamp: new Date(),
89 | });
90 | const doc = await db
91 | .collection("users")
92 | .doc(accounts[0])
93 | .collection("activechats")
94 | .doc(organization)
95 | .get();
96 | if (!doc.exists) {
97 | await db
98 | .collection("users")
99 | .doc(accounts[0])
100 | .collection("activechats")
101 | .doc(organization)
102 | .set({
103 | name: "Organization",
104 | ethAddress: organization,
105 | });
106 | await db
107 | .collection("users")
108 | .doc(organization)
109 | .collection("activechats")
110 | .doc(accounts[0])
111 | .set({
112 | name: "Employee",
113 | ethAddress: accounts[0],
114 | });
115 | }
116 | toast.success("Endorsement request sent!!");
117 | } catch (err) {
118 | console.log(err);
119 | }
120 | };
121 |
122 | export const reqEducationEndorsementFunc = async (education) => {
123 | const { institute, description, startdate, enddate } = education;
124 | const web3 = window.web3;
125 | const accounts = await web3.eth.getAccounts();
126 | var key;
127 | if (institute < accounts[0]) {
128 | key = institute + "#" + accounts[0];
129 | } else {
130 | key = accounts[0] + "#" + institute;
131 | }
132 | try {
133 | await db
134 | .collection("chats")
135 | .doc(key)
136 | .collection("chatmessages")
137 | .add({
138 | info: {
139 | req: "Education Endorsement Request",
140 | description,
141 | institute,
142 | startdate,
143 | enddate,
144 | ethAddress: accounts[0],
145 | },
146 | message: "Please endorse!!",
147 | sender: accounts[0],
148 | receiver: institute,
149 | timeStamp: new Date(),
150 | });
151 | const doc = await db
152 | .collection("users")
153 | .doc(accounts[0])
154 | .collection("activechats")
155 | .doc(institute)
156 | .get();
157 | if (!doc.exists) {
158 | await db
159 | .collection("users")
160 | .doc(accounts[0])
161 | .collection("activechats")
162 | .doc(institute)
163 | .set({
164 | name: "Institute",
165 | ethAddress: institute,
166 | });
167 | await db
168 | .collection("users")
169 | .doc(institute)
170 | .collection("activechats")
171 | .doc(accounts[0])
172 | .set({
173 | name: "Employee",
174 | ethAddress: accounts[0],
175 | });
176 | }
177 | toast.success("Endorsement request sent!!");
178 | } catch (err) {
179 | console.log(err);
180 | }
181 | };
182 |
183 | export const reqCertiEndorsementFunc = async (certification) => {
184 | const { name, organization, score } = certification;
185 | const web3 = window.web3;
186 | const accounts = await web3.eth.getAccounts();
187 | var key;
188 | if (organization < accounts[0]) {
189 | key = organization + "#" + accounts[0];
190 | } else {
191 | key = accounts[0] + "#" + organization;
192 | }
193 | try {
194 | await db
195 | .collection("chats")
196 | .doc(key)
197 | .collection("chatmessages")
198 | .add({
199 | info: {
200 | req: "Certification Endorsement Request",
201 | name,
202 | organization,
203 | score,
204 | ethAddress: accounts[0],
205 | },
206 | message: "Please endorse!!",
207 | sender: accounts[0],
208 | receiver: organization,
209 | timeStamp: new Date(),
210 | });
211 | const doc = await db
212 | .collection("users")
213 | .doc(accounts[0])
214 | .collection("activechats")
215 | .doc(organization)
216 | .get();
217 | if (!doc.exists) {
218 | await db
219 | .collection("users")
220 | .doc(accounts[0])
221 | .collection("activechats")
222 | .doc(organization)
223 | .set({
224 | name: "Certification Organization",
225 | ethAddress: organization,
226 | });
227 | await db
228 | .collection("users")
229 | .doc(organization)
230 | .collection("activechats")
231 | .doc(accounts[0])
232 | .set({
233 | name: "Certified Employee",
234 | ethAddress: accounts[0],
235 | });
236 | }
237 | toast.success("Endorsement request sent!!");
238 | } catch (err) {
239 | console.log(err);
240 | }
241 | };
242 |
--------------------------------------------------------------------------------
/src/components/ChatBody.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Image, Input, Loader } from "semantic-ui-react";
3 | import "./ChatBody.css";
4 | import { db } from "../firebase/firebase";
5 | import GetInfoModal from "./GetInfoModal";
6 |
7 | const senderDesign = {
8 | position: "relative",
9 | fontSize: "1rem",
10 | padding: "10px",
11 | backgroundColor: "#c5c6c7",
12 | color: "black",
13 | borderRadius: "10px",
14 | width: "fit-content",
15 | marginBottom: "23px",
16 | maxWidth: "60%",
17 | boxShadow: "inset 0 0 3px black",
18 | };
19 |
20 | const receiverDesign = {
21 | position: "relative",
22 | fontSize: "1rem",
23 | padding: "10px",
24 | backgroundColor: "rgba(0, 128, 128,.4)",
25 | borderRadius: "10px",
26 | width: "fit-content",
27 | marginBottom: "23px",
28 | marginLeft: "auto",
29 | color: "white",
30 | maxWidth: "60%",
31 | boxShadow: "inset 0 0 3px lightgray",
32 | };
33 |
34 | export default class ChatBody extends Component {
35 | state = {
36 | chats: [],
37 | loading: false,
38 | message: "",
39 | account: "",
40 | infomaodal: false,
41 | };
42 |
43 | componentDidMount = async () => {
44 | this.setState({ loading: true });
45 | const web3 = window.web3;
46 | const accounts = await web3.eth.getAccounts();
47 | this.setState({ account: accounts[0] });
48 | var key;
49 | const ethAddress = this.props.ethAddress;
50 | if (ethAddress < accounts[0]) {
51 | key = ethAddress + "#" + accounts[0];
52 | } else {
53 | key = accounts[0] + "#" + ethAddress;
54 | }
55 | await db
56 | .collection("chats")
57 | .doc(key)
58 | .collection("chatmessages")
59 | .orderBy("timeStamp", "desc")
60 | .onSnapshot((snapshot) =>
61 | this.setState({ chats: snapshot.docs.map((doc) => doc.data()) })
62 | );
63 | console.log(this.state.chats);
64 | this.setState({ loading: false });
65 | };
66 |
67 | sendMessage = async (e) => {
68 | e.preventDefault();
69 | const account = this.state.account;
70 | const ethAddress = this.props.ethAddress;
71 | var key;
72 | if (ethAddress < account) {
73 | key = ethAddress + "#" + account;
74 | } else {
75 | key = account + "#" + ethAddress;
76 | }
77 | await db.collection("chats").doc(key).collection("chatmessages").add({
78 | message: this.state.message,
79 | sender: account,
80 | receiver: ethAddress,
81 | timeStamp: new Date(),
82 | });
83 | this.setState({ message: "" });
84 | };
85 |
86 | handleKeyPress = (e) => {
87 | if (e.key === "Enter") this.sendMessage(e);
88 | };
89 |
90 | closeInfoModal = async () => {
91 | this.setState({ infomaodal: false });
92 | };
93 |
94 | render() {
95 | return this.state.loading ? (
96 |
97 | ) : (
98 | <>
99 | = 1
104 | ? this.state.chats[this.state.chats.length - 1].info
105 | : {}
106 | }
107 | admin={this.props.admin}
108 | isEndorsementReq={this.props.isEndorsementReq}
109 | org={this.props.org}
110 | />
111 |
112 |
this.setState({ infomaodal: true })}
119 | >
120 |
121 |
126 |
133 | {this.props.name}
134 |
135 |
136 |
144 | {this.props.ethAddress}
145 |
146 |
147 |
148 |
159 | {this.state.chats?.map((chat, index) => {
160 | return (
161 |
169 | {chat.sender !== "none" && (
170 | <>
171 |
172 |
184 | {chat.sender}
185 |
186 |
187 |
188 | >
189 | )}
190 | {chat.message}
191 |
192 |
202 | {new Date(chat.timeStamp?.toDate()).toUTCString()}
203 |
204 |
205 | );
206 | })}
207 |
208 |
209 |
216 | this.sendMessage(e),
224 | }}
225 | onChange={(e) => this.setState({ message: e.target.value })}
226 | style={{
227 | width: "100%",
228 | }}
229 | placeholder="Enter text..."
230 | className="design-chat-input"
231 | onKeyPress={this.handleKeyPress}
232 | />
233 |
234 | >
235 | );
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { toast } from "react-toastify";
4 | import { Menu, Segment, Image, Label, Icon } from "semantic-ui-react";
5 | import Admin from "../abis/Admin.json";
6 | import { Link } from "react-router-dom";
7 | import SearchBar from "./SearchBar";
8 | import GenererateQR from "./GenererateQR";
9 |
10 | class Navbar extends Component {
11 | state = { activeItem: "home", role: -1, account: "", showQr: false };
12 |
13 | componentDidMount = async () => {
14 | const web3 = await window.web3;
15 | console.log(web3);
16 | const accounts = await web3.eth.getAccounts();
17 | if (accounts) {
18 | this.setState({ account: accounts[0] });
19 | }
20 | const networkId = await web3.eth.net.getId();
21 | const AdminData = await Admin.networks[networkId];
22 | if (AdminData) {
23 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
24 | const isEmployee = await admin?.methods?.isEmployee(accounts[0]).call();
25 | const isOrganizationEndorser = await admin?.methods
26 | ?.isOrganizationEndorser(accounts[0])
27 | .call();
28 | const owner = await admin?.methods?.owner().call();
29 | var role = -1;
30 | if (accounts[0] === owner) {
31 | role = 0;
32 | } else if (isEmployee) {
33 | role = 1;
34 | } else if (isOrganizationEndorser) {
35 | role = 2;
36 | }
37 | this.setState({ role });
38 | } else {
39 | toast.error("The Admin Contract does not exist on this network!");
40 | }
41 | };
42 |
43 | handleItemClick = (e, { name }) => this.setState({ activeItem: name });
44 |
45 | closeQRModal = () => {
46 | this.setState({ showQr: false });
47 | };
48 |
49 | render() {
50 | const { activeItem } = this.state;
51 | const roles = ["Admin", "Employee", "Organization"];
52 |
53 | return (
54 | <>
55 |
59 |
68 |
74 |
79 |
93 |
94 |
95 |
96 |
100 |
101 |
102 | {this.state.role === 0 && (
103 | <>
104 |
111 |
118 |
125 |
132 | >
133 | )}
134 | {this.state.role === 1 && (
135 | <>
136 |
143 |
150 |
157 | >
158 | )}
159 |
160 | {this.state.role === 2 && (
161 | <>
162 |
169 |
176 |
183 |
190 | >
191 | )}
192 |
193 | {this.state.role === -1 && (
194 | <>
195 |
202 |
209 | >
210 | )}
211 |
212 |
213 |
214 | {this.state.role === -1 ? "No Role" : roles[this.state.role]}
215 |
216 |
217 |
218 |
219 | {this.state.account}
220 |
221 |
222 | this.setState({ showQr: true })}
227 | />
228 |
229 |
230 |
231 |
232 | >
233 | );
234 | }
235 | }
236 |
237 | export default withRouter(Navbar);
238 |
--------------------------------------------------------------------------------
/src/contracts/Employee.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.5.0 <0.9.0;
2 |
3 | contract Employee {
4 | address admin;
5 | address employee_address;
6 | string description;
7 | string location;
8 | uint256[] public overallEndorsement;
9 | uint256 endorsecount;
10 | string name;
11 |
12 | constructor(
13 | address _admin,
14 | address _employee_address,
15 | string memory _name,
16 | string memory _description,
17 | string memory _location
18 | ) public {
19 | admin = _admin;
20 | name = _name;
21 | employee_address = _employee_address;
22 | description = _description;
23 | location = _location;
24 | endorsecount = 0;
25 | }
26 |
27 | modifier OnlyEmployee() {
28 | require(msg.sender == employee_address);
29 | _;
30 | }
31 |
32 | function getEmployeeInfo()
33 | public
34 | view
35 | returns (
36 | address,
37 | string memory,
38 | string memory,
39 | string memory,
40 | uint256,
41 | uint256
42 | )
43 | {
44 | return (employee_address, name, description, location, 0, endorsecount);
45 | }
46 |
47 | function editInfo(
48 | string memory _name,
49 | string memory _descrip,
50 | string memory _location
51 | ) public OnlyEmployee {
52 | name = _name;
53 | description = _descrip;
54 | location = _location;
55 | }
56 |
57 | /*********************************************************SKILLS SECTION**********************************************************/
58 |
59 | struct skillInfo {
60 | string name;
61 | uint256 overall_percentage;
62 | string experience;
63 | bool endorsed;
64 | address endorser_address;
65 | string review;
66 | bool visible;
67 | }
68 |
69 | mapping(string => skillInfo) skillmap;
70 | string[] skills;
71 |
72 | function addSkill(string memory _name, string memory _experience)
73 | public
74 | OnlyEmployee
75 | {
76 | skillInfo memory employeeSkillSet;
77 | employeeSkillSet.name = _name;
78 | employeeSkillSet.experience = _experience;
79 | employeeSkillSet.overall_percentage = 0;
80 | employeeSkillSet.endorsed = false;
81 | employeeSkillSet.visible = true;
82 | skillmap[_name] = employeeSkillSet;
83 | skills.push(_name);
84 | }
85 |
86 | function endorseSkill(
87 | string memory _name,
88 | uint256 _overall_percentage,
89 | string memory _review
90 | ) public {
91 | require(skillmap[_name].visible);
92 | skillmap[_name].overall_percentage = _overall_percentage;
93 | overallEndorsement.push(_overall_percentage);
94 | endorsecount = endorsecount + 1;
95 | skillmap[_name].endorsed = true;
96 | skillmap[_name].endorser_address = msg.sender;
97 | skillmap[_name].review = _review;
98 | }
99 |
100 | function getSkillByName(string memory _name)
101 | private
102 | view
103 | returns (
104 | string memory,
105 | uint256,
106 | string memory,
107 | bool,
108 | address,
109 | string memory,
110 | bool
111 | )
112 | {
113 | return (
114 | skillmap[_name].name,
115 | skillmap[_name].overall_percentage,
116 | skillmap[_name].experience,
117 | skillmap[_name].endorsed,
118 | skillmap[_name].endorser_address,
119 | skillmap[_name].review,
120 | skillmap[_name].visible
121 | );
122 | }
123 |
124 | function getSkillCount() public view returns (uint256) {
125 | return skills.length;
126 | }
127 |
128 | function getSkillByIndex(uint256 _index)
129 | public
130 | view
131 | returns (
132 | string memory,
133 | uint256,
134 | string memory,
135 | bool,
136 | address,
137 | string memory,
138 | bool
139 | )
140 | {
141 | return getSkillByName(skills[_index]);
142 | }
143 |
144 | function deleteSkill(string memory _name) public OnlyEmployee {
145 | skillmap[_name].visible = !skillmap[_name].visible;
146 | }
147 |
148 | /*********************************************************CERTIFICATION SECTION**********************************************************/
149 |
150 | struct certificationInfo {
151 | string name;
152 | address organization;
153 | uint256 score;
154 | bool endorsed;
155 | bool visible;
156 | }
157 |
158 | mapping(string => certificationInfo) certificationmap;
159 | string[] certifications;
160 |
161 | function addCertification(
162 | string memory _name,
163 | address _organization,
164 | uint256 _score
165 | ) public OnlyEmployee {
166 | certificationInfo memory newcertificationInfo;
167 | newcertificationInfo.name = _name;
168 | newcertificationInfo.organization = _organization;
169 | newcertificationInfo.score = _score;
170 | newcertificationInfo.endorsed = false;
171 | newcertificationInfo.visible = true;
172 | certificationmap[_name] = newcertificationInfo;
173 | certifications.push(_name);
174 | }
175 |
176 | function endorseCertification(string memory _name) public {
177 | require(msg.sender == certificationmap[_name].organization);
178 | certificationmap[_name].endorsed = true;
179 | }
180 |
181 | function getCertificationByName(string memory _name)
182 | private
183 | view
184 | returns (
185 | string memory,
186 | address,
187 | uint256,
188 | bool,
189 | bool
190 | )
191 | {
192 | return (
193 | certificationmap[_name].name,
194 | certificationmap[_name].organization,
195 | certificationmap[_name].score,
196 | certificationmap[_name].endorsed,
197 | certificationmap[_name].visible
198 | );
199 | }
200 |
201 | function getCertificationCount() public view returns (uint256) {
202 | return certifications.length;
203 | }
204 |
205 | function getCertificationByIndex(uint256 _index)
206 | public
207 | view
208 | returns (
209 | string memory,
210 | address,
211 | uint256,
212 | bool,
213 | bool
214 | )
215 | {
216 | return getCertificationByName(certifications[_index]);
217 | }
218 |
219 | function deleteCertification(string memory _name) public OnlyEmployee {
220 | certificationmap[_name].visible = !certificationmap[_name].visible;
221 | }
222 |
223 | /********************************************************************Work Experience Section********************************************************************/
224 |
225 | struct workexpInfo {
226 | string role;
227 | address organization;
228 | string startdate;
229 | string enddate;
230 | bool endorsed;
231 | string description;
232 | bool visible;
233 | }
234 |
235 | mapping(address => workexpInfo) workexpmap;
236 | address[] workexps;
237 |
238 | function addWorkExp(
239 | string memory _role,
240 | address _organization,
241 | string memory _startdate,
242 | string memory _enddate,
243 | string memory _description
244 | ) public OnlyEmployee {
245 | workexpInfo memory newworkexp;
246 | newworkexp.role = _role;
247 | newworkexp.organization = _organization;
248 | newworkexp.startdate = _startdate;
249 | newworkexp.enddate = _enddate;
250 | newworkexp.endorsed = false;
251 | newworkexp.visible = true;
252 | newworkexp.description = _description;
253 | workexpmap[_organization] = newworkexp;
254 | workexps.push(_organization);
255 | }
256 |
257 | function endorseWorkExp() public {
258 | require(workexpmap[msg.sender].organization != address(0x0));
259 | workexpmap[msg.sender].endorsed = true;
260 | }
261 |
262 | function getWorkExpByAddress(address _organization)
263 | private
264 | view
265 | returns (
266 | string memory,
267 | address,
268 | string memory,
269 | string memory,
270 | bool,
271 | string memory,
272 | bool
273 | )
274 | {
275 | return (
276 | workexpmap[_organization].role,
277 | workexpmap[_organization].organization,
278 | workexpmap[_organization].startdate,
279 | workexpmap[_organization].enddate,
280 | workexpmap[_organization].endorsed,
281 | workexpmap[_organization].description,
282 | workexpmap[_organization].visible
283 | );
284 | }
285 |
286 | function getWorkExpCount() public view returns (uint256) {
287 | return workexps.length;
288 | }
289 |
290 | function getWorkExpByIndex(uint256 _index)
291 | public
292 | view
293 | returns (
294 | string memory,
295 | address,
296 | string memory,
297 | string memory,
298 | bool,
299 | string memory,
300 | bool
301 | )
302 | {
303 | return getWorkExpByAddress(workexps[_index]);
304 | }
305 |
306 | function deleteWorkExp(address org) public OnlyEmployee {
307 | workexpmap[org].visible = false;
308 | }
309 |
310 | /********************************************************************Education Section********************************************************************/
311 |
312 | struct educationInfo {
313 | address institute;
314 | string startdate;
315 | string enddate;
316 | bool endorsed;
317 | string description;
318 | }
319 |
320 | mapping(address => educationInfo) educationmap;
321 | address[] educations;
322 |
323 | function addEducation(
324 | address _institute,
325 | string memory _startdate,
326 | string memory _enddate,
327 | string memory _description
328 | ) public OnlyEmployee {
329 | educationInfo memory newEducation;
330 | newEducation.institute = _institute;
331 | newEducation.startdate = _startdate;
332 | newEducation.enddate = _enddate;
333 | newEducation.endorsed = false;
334 | newEducation.description = _description;
335 | educationmap[_institute] = newEducation;
336 | educations.push(_institute);
337 | }
338 |
339 | function endorseEducation() public {
340 | require(educationmap[msg.sender].institute != address(0x0));
341 | educationmap[msg.sender].endorsed = true;
342 | }
343 |
344 | function getEducationByAddress(address _institute)
345 | private
346 | view
347 | returns (
348 | address,
349 | string memory,
350 | string memory,
351 | bool,
352 | string memory
353 | )
354 | {
355 | return (
356 | educationmap[_institute].institute,
357 | educationmap[_institute].startdate,
358 | educationmap[_institute].enddate,
359 | educationmap[_institute].endorsed,
360 | educationmap[_institute].description
361 | );
362 | }
363 |
364 | function getEducationCount() public view returns (uint256) {
365 | return educations.length;
366 | }
367 |
368 | function getEducationByIndex(uint256 _index)
369 | public
370 | view
371 | returns (
372 | address,
373 | string memory,
374 | string memory,
375 | bool,
376 | string memory
377 | )
378 | {
379 | return getEducationByAddress(educations[_index]);
380 | }
381 | }
382 |
--------------------------------------------------------------------------------