├── src
├── App.css
├── demo
├── Contracts
│ ├── .gitkeep
│ ├── demo
│ ├── Migrations.sol
│ ├── OrganizationEndorser.sol
│ ├── Skills.sol
│ ├── Admin.sol
│ └── Employee.sol
├── components
│ ├── demo
│ ├── LoadComp.css
│ ├── ChatBody.css
│ ├── NoChats.js
│ ├── OrgEndCard.css
│ ├── SkillCard.css
│ ├── LineChart.js
│ ├── GenererateQR.js
│ ├── Search.css
│ ├── EmployeeCard.css
│ ├── OrgEndCard.js
│ ├── CodeforcesGraph.js
│ ├── Modals.css
│ ├── LoadComp.js
│ ├── SearchEmp.js
│ ├── ScanQR.js
│ ├── SearchBar.js
│ ├── GetSkillsModals.js
│ ├── SkillCard.js
│ ├── GetEmployeeModal.js
│ ├── GetEditFieldModal.js
│ ├── GetCertificationModal.js
│ ├── GetEducationModal.js
│ ├── GetWorkExpModal.js
│ ├── ChatBody.js
│ ├── Navbar.js
│ └── EmployeeCard.js
├── pages
│ ├── Admin
│ │ ├── demo
│ │ ├── AllEmployees.js
│ │ ├── AllOrganizationEndorser.js
│ │ ├── Admin.css
│ │ ├── Notifications.js
│ │ └── CreateUser.js
│ ├── Employee
│ │ ├── demo
│ │ ├── Employee.css
│ │ ├── UpdateProfile.css
│ │ └── Notifications.js
│ ├── No Role
│ │ ├── demo
│ │ ├── Notifications.css
│ │ ├── NoRole.css
│ │ ├── Notifications.js
│ │ └── NoRole.js
│ ├── Get Routes
│ │ ├── demo
│ │ ├── GetOrg.css
│ │ ├── Employee.css
│ │ └── GetOrg.js
│ └── Organization Endorser
│ │ ├── demo
│ │ ├── EndorsePage.css
│ │ ├── Organization.css
│ │ ├── Organization.js
│ │ ├── Notifications.js
│ │ ├── EndorseSkill.js
│ │ └── EndorseSection.js
├── setupTests.js
├── App.test.js
├── reportWebVitals.js
├── index.css
├── index.js
├── MetaMaskGuide.js
└── App.js
├── migrations
├── .gitkeep
├── 1_initial_migration.js
└── 2_deploy_contracts.js
├── .babelrc
├── dotenv
├── .env
├── .gitignore
├── package.json
├── README.md
└── truffle-config.js
/src/App.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/migrations/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Contracts/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Contracts/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/Admin/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/Employee/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/No Role/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/Get Routes/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/demo:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-es2015", "stage-2", "stage-3"]
3 | }
--------------------------------------------------------------------------------
/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | const Migrations = artifacts.require("Migrations");
2 |
3 | module.exports = function (deployer) {
4 | deployer.deploy(Migrations);
5 | };
--------------------------------------------------------------------------------
/dotenv:
--------------------------------------------------------------------------------
1 | INFURA_API_KEY = "https://goerli.infura.io/v3/22035631f58a401f92c35fc534df3af4"
2 | MNEMONIC = "rhythm excuse judge rebuild frost code surge month horror isolate wool brain"
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | INFURA_API_KEY = "https://goerli.infura.io/v3/22035631f58a401f92c35fc534df3af4"
2 | MNEMONIC = "rhythm excuse judge rebuild frost code surge month horror isolate wool brain"
3 | GENERATE_SOURCEMAP=false
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | };
--------------------------------------------------------------------------------
/.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 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
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 | const root= ReactDOM.createRoot(document.getElementById("root"));
10 | root.render(
11 | //
12 |
13 | //
14 |
15 | );
16 |
17 | // If you want to start measuring performance in your app, pass a function
18 | // to log results (for example: reportWebVitals(console.log))
19 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
20 | reportWebVitals();
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/No Role/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/Get Routes/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 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "copy-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "@truffle/hdwallet-provider": "^2.1.9",
10 | "dotenv": "^16.0.3",
11 | "ganache": "^7.7.7",
12 | "react": ">=16.8.0",
13 | "react-dom": ">=16.8.8",
14 | "react-scripts": "5.0.1",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "peerDependencies": {
18 | "react": ">=16.8.0",
19 | "react-dom": ">=16.8.8"
20 | },
21 | "scripts": {
22 | "start": "react-scripts start",
23 | "build": "GENERATE_SOURCEMAP=false react-scripts build",
24 | "test": "react-scripts test",
25 | "eject": "react-scripts eject"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
33 |
34 |
35 | );
36 | }
37 | }
--------------------------------------------------------------------------------
/src/Contracts/OrganizationEndorser.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.5.0 <0.9.0;
3 |
4 | contract OrganizationEndorser {
5 | address admin;
6 | string name;
7 | address organization_address;
8 | string description;
9 | string location;
10 |
11 | constructor(
12 | address _admin,
13 | address _organization_address,
14 | string memory _name,
15 | string memory _description,
16 | string memory _location
17 | ) public {
18 | admin = _admin;
19 | name = _name;
20 | organization_address = _organization_address;
21 | description = _description;
22 | location = _location;
23 | }
24 |
25 | function getOrganizationInfo()
26 | public
27 | view
28 | returns (
29 | string memory,
30 | address,
31 | string memory,
32 | string memory
33 | )
34 | {
35 | return (name, organization_address, description, location);
36 | }
37 |
38 | address[] allEmployees;
39 |
40 | function addEmployees(address employee_address) public {
41 | require(msg.sender == organization_address);
42 | allEmployees.push(employee_address);
43 | }
44 |
45 | function totalEmployees() public view returns (uint256) {
46 | return allEmployees.length;
47 | }
48 |
49 | function getEmployeeByIndex(uint256 index) public view returns (address) {
50 | return allEmployees[index];
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Contracts/Skills.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.5.0 <0.9.0;
3 |
4 | contract Skills {
5 | mapping(string => address[]) skillmap;
6 | string[] skill;
7 |
8 | function addEmployeeToSkill(string memory _name, address _employee) public {
9 | if (skillmap[_name].length == 0) {
10 | skill.push(_name);
11 | }
12 | skillmap[_name].push(_employee);
13 | }
14 |
15 | function getSkillLength() public view returns (uint256) {
16 | return skill.length;
17 | }
18 |
19 | function getSkillsByIndex(uint256 index) public view returns (string memory) {
20 | return skill[index];
21 | }
22 |
23 | function getTotalEmployeeInSkillByIndex(uint256 index)
24 | public
25 | view
26 | returns (uint256)
27 | {
28 | return skillmap[skill[index]].length;
29 | }
30 |
31 | function getTotalEmployeeInSkillByName(string memory _name)
32 | public
33 | view
34 | returns (uint256)
35 | {
36 | return skillmap[_name].length;
37 | }
38 |
39 | function getEmployeeInSkillByIndex(uint256 skill_index, uint256 emp_index)
40 | public
41 | view
42 | returns (address)
43 | {
44 | return skillmap[skill[skill_index]][emp_index];
45 | }
46 |
47 | function getEmployeeBySkillName(string memory _name, uint256 emp_index)
48 | public
49 | view
50 | returns (address)
51 | {
52 | return skillmap[_name][emp_index];
53 | }
54 | }
--------------------------------------------------------------------------------
/src/components/GenererateQR.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import QRCode from "qrcode.react";
3 |
4 | import "./Modals.css";
5 | import { Button, Header, Modal } from "semantic-ui-react";
6 |
7 | export default class GenererateQR extends Component {
8 | state = {
9 | qr: "",
10 | };
11 |
12 | componentDidMount = async () => {
13 | const web3 = window.web3;
14 | const accounts = await web3.eth.getAccounts();
15 | try {
16 | const res = await QRCode.toDataURL(accounts[0]);
17 | this.setState({ qr: res });
18 | } catch (err) {
19 | console.log(err);
20 | }
21 | };
22 |
23 | render() {
24 | return (
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
47 |
48 | );
49 | }
50 | }
--------------------------------------------------------------------------------
/src/pages/Get Routes/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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;
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/components/LoadComp.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./LoadComp.css";
3 |
4 | function LoadComp() {
5 | return (
6 |
7 |
38 |
39 | );
40 | }
41 |
42 | export default LoadComp;
--------------------------------------------------------------------------------
/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);
--------------------------------------------------------------------------------
/src/pages/Get Routes/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);
--------------------------------------------------------------------------------
/src/Contracts/Admin.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.5.0 <0.9.0;
3 | import "./Employee.sol";
4 | import "./OrganizationEndorser.sol";
5 |
6 | contract Admin {
7 | address public owner;
8 |
9 | constructor() public {
10 | owner = msg.sender;
11 | }
12 |
13 | modifier onlyOwner() {
14 | require(msg.sender == owner);
15 | _;
16 | }
17 |
18 | mapping(address => address) registeredEmployeesmap;
19 | mapping(address => address) registeredOrganizationmap;
20 | address[] registeredEmployees;
21 | address[] registeredOrganization;
22 |
23 | function registerUser(
24 | address EthAddress,
25 | string memory Name,
26 | string memory Location,
27 | string memory Description,
28 | uint256 Role
29 | ) public onlyOwner {
30 | if (Role == 1) {
31 | Employee newEmployee = new Employee(
32 | owner,
33 | EthAddress,
34 | Name,
35 | Location,
36 | Description
37 | );
38 | registeredEmployeesmap[EthAddress] = address(newEmployee);
39 | registeredEmployees.push(EthAddress);
40 | } else {
41 | OrganizationEndorser newOrganizationEndorser = new OrganizationEndorser(
42 | owner,
43 | EthAddress,
44 | Name,
45 | Location,
46 | Description
47 | );
48 | registeredOrganizationmap[EthAddress] = address(newOrganizationEndorser);
49 | registeredOrganization.push(EthAddress);
50 | }
51 | }
52 |
53 | /****************************************************************USER SECTION**************************************************/
54 |
55 | function isEmployee(address _employeeAddress) public view returns (bool) {
56 | return registeredEmployeesmap[_employeeAddress] != address(0x0);
57 | }
58 |
59 | function isOrganizationEndorser(address _organizationEndorser)
60 | public
61 | view
62 | returns (bool)
63 | {
64 | return registeredOrganizationmap[_organizationEndorser] != address(0x0);
65 | }
66 |
67 | function employeeCount() public view returns (uint256) {
68 | return registeredEmployees.length;
69 | }
70 |
71 | function getEmployeeContractByAddress(address _employee)
72 | public
73 | view
74 | returns (address)
75 | {
76 | return registeredEmployeesmap[_employee];
77 | }
78 |
79 | function getEmployeeContractByIndex(uint256 index)
80 | public
81 | view
82 | returns (address)
83 | {
84 | return getEmployeeContractByAddress(registeredEmployees[index]);
85 | }
86 |
87 | function OrganizationEndorserCount() public view returns (uint256) {
88 | return registeredOrganization.length;
89 | }
90 |
91 | function getOrganizationContractByAddress(address _organization)
92 | public
93 | view
94 | returns (address)
95 | {
96 | return registeredOrganizationmap[_organization];
97 | }
98 |
99 | function getOrganizationContractByIndex(uint256 index)
100 | public
101 | view
102 | returns (address)
103 | {
104 | return getOrganizationContractByAddress(registeredOrganization[index]);
105 | }
106 | }
--------------------------------------------------------------------------------
/src/pages/No Role/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 | }
--------------------------------------------------------------------------------
/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 |
101 |
102 | );
103 | }
104 |
105 | export default ScanQR;
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/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 |
113 |
114 | );
115 | }
116 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/No Role/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/No Role/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 | address: "",
65 | });
66 | };
67 |
68 | render() {
69 | return (
70 |
158 | );
159 | }
160 | }
161 |
162 | export default withRouter(NoRole);
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Abstract
2 |
3 | Recently, blockchain technology has gained considerable attention from researchers and practitioners. This is mainly due to its unique features including decentralization, security, reliability, and data integrity. The current centralized educational data management system results in problems like malicious tampering, low cost of diploma fabrication, and high cost of certificate and identity verification. The art of decentralized blockchain technology can be applied to solve these problems and many more. Blockchain provides a creative approach to storing information, executing transactions, conducting tasks, and building trust. In this project, we tried to solve the shortcomings of the existing centralized and manual systems and propose a blockchain-based framework for secure and reliable student's record management.
4 |
5 | # Objective
6 |
7 | * To reduce the university’s large amount of paper and human work in student information
8 | management.
9 | * To keep track of every academic detail of the student throughout their academic journey
10 | * To offer a model for the academic certificate/degree issuing and verification using blockchain
11 | technology.
12 | * To issue digital certificates gained during online courses/contests/competitions and be verified using
13 | the blockchain.
14 | * To present the certificates online for further reference.
15 | * To help students create an online application portfolio without writing a resume.
16 |
17 | # Methodology
18 |
19 | * The students send their original documents and additional certificates required for verification to the university.
20 | * Returns a unique hash transaction ID for the verification of the certificate.
21 | * Stores hash address of each person; verifier can see all the certificates listed and verify them individually.
22 | * Also stores extra-curricular certifications, platform ratings, work experiences etc.
23 | * The industries and future employers access the verified credentials by using the transaction id and unique candidate id (hash address).
24 |
25 | ## Technology Stack
26 |
27 | * **Front-end**
28 | 1. React
29 | 2. Redux
30 | 3. Metamask
31 | 4. NodeJS
32 | 5. HTML/CSS
33 |
34 | * **Back-end**
35 | 1. Solidity
36 | 2. Truffle
37 | 3. Ganache
38 | 4. Web3.js
39 |
40 | # Implementation
41 |
42 | ### 1. Home Screen
43 |
44 | 
45 |
46 | 
47 |
48 | ### 2. Admin Page
49 |
50 | 
51 |
52 | ### 3. Register New User using Metamask
53 |
54 | 
55 | 
56 |
57 | ### 4. Registered Users and Endorsers
58 |
59 | 
60 | 
61 |
62 |
63 | # Results and Analysis
64 |
65 | * **Improved data security** - One of the main benefits of using a blockchain to manage student records is that it can provide a secure and tamper-proof way to store and access this sensitive data.
66 | * **Increased transparency** - With a blockchain-based student management system, all parties involved inthe process would be able to see a complete and accurate record of a student's academic history.
67 | * **Improved accessibility** - Students are able to easily access and share their academic records with anyinstitution that needed them, regardless of where they had previously studied.
68 | * **Degree Validation** - Using blockchain technology can provide certificates to students via a mobile application and students can surely share their credentials with others.
69 | * **Accuracy and integrity** - One of the main benefits of using a blockchain is that it allows for the creation of a tamper-evident record of data.
70 |
71 | # Conclusion
72 |
73 | The use of blockchain technology in education is a good and right decision. There are four problem descriptions can be resolved with four conclusions:
74 |
75 | 1. **Diploma counterfeiting**:-The increasing percentage of difficulty in counterfeiting a certificate will increase.
76 |
77 | 2. **Reduced costs**:-It will be easier and cheaper to verify the authenticity of a candidate's certificate.
78 |
79 | 3. **Time Efficiency**:- The certificate authenticity verification process will not take long; in a matter of minutes, the verification process can be completed.
80 |
81 | 4. **Competence of workers**:- The use of blockchain technology produces qualified and competent workers. Of course, it is blockchain technology that makes it difficult to fake a certificate.
82 |
83 | # Future Scope
84 |
85 | * **Streamlined Enrollment and Admission Processes:** Educational institutions can securely share and verify student credentials, transcripts, and other necessary documents, reducing the time and effort required for manual verification. This enhances the efficiency and speed of the enrollment process.
86 |
87 | * **Verifier Application:** Future includes adding a QR code scanner directly into the application, and the student can present a QR code to the verifier, thus the verification process will be instant without having to manually enter a serial number or passcode if preferred.
88 |
89 | * **Personalized Learning Paths and Recommendations:** AI algorithms can analyze student performance data, identify strengths and weaknesses, and offer tailored recommendations for academic or career development. This enables a more individualized and adaptive learning experience.
90 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { toast, ToastContainer } from "react-toastify";
3 | import Web3 from "web3/dist/web3.min.js";
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 |
28 | function App() {
29 | const [isMeta, setisMeta] = useState(false);
30 | const [isEmployee, setisEmployee] = useState(false);
31 | const [account, setaccount] = useState("");
32 | const [isOrganizationEndorser, setisOrganizationEndorser] = useState(false);
33 | const [isOwner, setisOwner] = useState(false);
34 | const [loadcomp, setloadcomp] = useState(false);
35 |
36 | const loadBlockChainData = async () => {
37 | const web3 = window.web3;
38 | const accounts = await web3.eth.getAccounts();
39 | if (accounts) {
40 | setaccount(accounts[0]);
41 | }
42 | const networkId = await web3.eth.net.getId();
43 | const AdminData = await Admin.networks[networkId];
44 | if (AdminData) {
45 | const admin = await new web3.eth.Contract(Admin.abi, AdminData.address);
46 | const isEmployee = await admin?.methods?.isEmployee(accounts[0]).call();
47 | const isOrganizationEndorser = await admin?.methods
48 | ?.isOrganizationEndorser(accounts[0])
49 | .call();
50 | const owner = await admin?.methods?.owner().call();
51 | setisEmployee(isEmployee);
52 | setisOrganizationEndorser(isOrganizationEndorser);
53 | setisOwner(owner === accounts[0]);
54 | } else {
55 | toast.error("The Admin Contract does not exist on this network!");
56 | }
57 | };
58 |
59 | useEffect(() => {
60 | const func = async () => {
61 | setisMeta(true);
62 | setloadcomp(true);
63 | if (window.ethereum) {
64 | await window.ethereum.request({
65 | method: "eth_requestAccounts",
66 | });
67 | window.web3 = await new Web3(window.ethereum);
68 | await loadBlockChainData();
69 | } else if (window.web3) {
70 | window.web3 = await new Web3(window.web3.currentProvider);
71 | await loadBlockChainData();
72 | } else {
73 | setisMeta(false);
74 | }
75 | setloadcomp(false);
76 | };
77 | func();
78 | return () => {
79 | //
80 | };
81 | }, []);
82 |
83 | const adminRoutes = () => {
84 | return (
85 |
86 |
87 |
92 |
93 |
94 |
95 | );
96 | };
97 |
98 | const employeeRoutes = () => {
99 | return (
100 |
101 |
102 |
103 |
104 |
105 | );
106 | };
107 |
108 | const isOrganizationEndorserRoutes = () => {
109 | return (
110 |
111 |
112 |
113 |
114 |
115 |
116 | );
117 | };
118 |
119 | const noRoleRoutes = () => {
120 | return (
121 |
122 |
123 |
124 |
125 | );
126 | };
127 |
128 | const renderRoutes = () => {
129 | if (isOwner) return adminRoutes();
130 | else if (isEmployee) return employeeRoutes();
131 | else if (isOrganizationEndorser) return isOrganizationEndorserRoutes();
132 | else return noRoleRoutes();
133 | };
134 |
135 | return (
136 |
137 | {loadcomp ? (
138 |
139 | ) : isMeta && account !== "" ? (
140 |
141 |
142 |
143 |
144 |
145 |
150 |
151 | {renderRoutes()}
152 |
153 |
154 |
155 | ) : (
156 |
157 | )}
158 |
159 | );
160 | }
161 |
162 | export default App;
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/src/pages/Organization Endorser/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 | }
--------------------------------------------------------------------------------
/truffle-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Use this file to configure your truffle project. It's seeded with some
3 | * common settings for different networks and features like migrations,
4 | * compilation, and testing. Uncomment the ones you need or modify
5 | * them to suit your project as necessary.
6 | *
7 | * More information about configuration can be found at:
8 | *
9 | * https://trufflesuite.com/docs/truffle/reference/configuration
10 | *
11 | * Hands-off deployment with Infura
12 | * --------------------------------
13 | *
14 | * Do you have a complex application that requires lots of transactions to deploy?
15 | * Use this approach to make deployment a breeze 🏖️:
16 | *
17 | * Infura deployment needs a wallet provider (like @truffle/hdwallet-provider)
18 | * to sign transactions before they're sent to a remote public node.
19 | * Infura accounts are available for free at 🔍: https://infura.io/register
20 | *
21 | * You'll need a mnemonic - the twelve word phrase the wallet uses to generate
22 | * public/private key pairs. You can store your secrets 🤐 in a .env file.
23 | * In your project root, run `$ npm install dotenv`.
24 | * Create .env (which should be .gitignored) and declare your MNEMONIC
25 | * and Infura PROJECT_ID variables inside.
26 | * For example, your .env file will have the following structure:
27 | *
28 | * MNEMONIC =
29 | * PROJECT_ID =
30 | *
31 | * Deployment with Truffle Dashboard (Recommended for best security practice)
32 | * --------------------------------------------------------------------------
33 | *
34 | * Are you concerned about security and minimizing rekt status 🤔?
35 | * Use this method for best security:
36 | *
37 | * Truffle Dashboard lets you review transactions in detail, and leverages
38 | * MetaMask for signing, so there's no need to copy-paste your mnemonic.
39 | * More details can be found at 🔎:
40 | *
41 | * https://trufflesuite.com/docs/truffle/getting-started/using-the-truffle-dashboard/
42 | */
43 |
44 | // require('dotenv').config();
45 | // const { MNEMONIC, PROJECT_ID } = process.env;
46 |
47 | // const HDWalletProvider = require('@truffle/hdwallet-provider');
48 |
49 | // module.exports = {
50 | /**
51 | * Networks define how you connect to your ethereum client and let you set the
52 | * defaults web3 uses to send transactions. If you don't specify one truffle
53 | * will spin up a managed Ganache instance for you on port 9545 when you
54 | * run `develop` or `test`. You can ask a truffle command to use a specific
55 | * network from the command line, e.g
56 | *
57 | * $ truffle test --network
58 | */
59 |
60 | // networks: {
61 | // Useful for testing. The `development` name is special - truffle uses it by default
62 | // if it's defined here and no other network is specified at the command line.
63 | // You should run a client (like ganache, geth, or parity) in a separate terminal
64 | // tab if you use this network and you must also set the `host`, `port` and `network_id`
65 | // options below to some value.
66 | //
67 | // development: {
68 | // host: "127.0.0.1", // Localhost (default: none)
69 | // port: 8545, // Standard Ethereum port (default: none)
70 | // network_id: "*", // Any network (default: none)
71 | // },
72 | //
73 | // An additional network, but with some advanced options…
74 | // advanced: {
75 | // port: 8777, // Custom port
76 | // network_id: 1342, // Custom network
77 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000)
78 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
79 | // from: , // Account to send transactions from (default: accounts[0])
80 | // websocket: true // Enable EventEmitter interface for web3 (default: false)
81 | // },
82 | //
83 | // Useful for deploying to a public network.
84 | // Note: It's important to wrap the provider as a function to ensure truffle uses a new provider every time.
85 | // goerli: {
86 | // provider: () => new HDWalletProvider(MNEMONIC, `https://goerli.infura.io/v3/${PROJECT_ID}`),
87 | // network_id: 5, // Goerli's id
88 | // confirmations: 2, // # of confirmations to wait between deployments. (default: 0)
89 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
90 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
91 | // },
92 | //
93 | // Useful for private networks
94 | // private: {
95 | // provider: () => new HDWalletProvider(MNEMONIC, `https://network.io`),
96 | // network_id: 2111, // This network is yours, in the cloud.
97 | // production: true // Treats this network as if it was a public net. (default: false)
98 | // }
99 | // },
100 |
101 | // Set default mocha options here, use special reporters, etc.
102 | // mocha: {
103 | // // timeout: 100000
104 | // },
105 |
106 | // Configure your compilers
107 | // compilers: {
108 | // solc: {
109 | // version: "0.8.19", // Fetch exact version from solc-bin (default: truffle's version)
110 | // // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
111 | // // settings: { // See the solidity docs for advice about optimization and evmVersion
112 | // // optimizer: {
113 | // // enabled: false,
114 | // // runs: 200
115 | // // },
116 | // // evmVersion: "byzantium"
117 | // // }
118 | // }
119 | // },
120 |
121 | // Truffle DB is currently disabled by default; to enable it, change enabled:
122 | // false to enabled: true. The default storage location can also be
123 | // overridden by specifying the adapter settings, as shown in the commented code below.
124 | //
125 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should
126 | // make a backup of your artifacts to a safe location before enabling this feature.
127 | //
128 | // After you backed up your artifacts you can utilize db by running migrate as follows:
129 | // $ truffle migrate --reset --compile-all
130 | //
131 | // db: {
132 | // enabled: false,
133 | // host: "127.0.0.1",
134 | // adapter: {
135 | // name: "indexeddb",
136 | // settings: {
137 | // directory: ".db"
138 | // }
139 | // }
140 | // }
141 | // };
142 |
143 | // require('dotenv').config();
144 | const HDWalletProvider = require('@truffle/hdwallet-provider');
145 | // const { INFURA_API_KEY, MNEMONIC } = process.env;
146 | const MNEMONIC = 'rhythm excuse judge rebuild frost code surge month horror isolate wool brain';
147 |
148 | module.exports = {
149 | contracts_directory: "./src/contracts/",
150 | contacts_build_directory: "./src/abis/",
151 | networks: {
152 | developement: {
153 | host: "127.0.0.1",
154 | port: 7545,
155 | network_id: "5777"
156 | }
157 | // goerli: {
158 | // provider: () => new HDWalletProvider(MNEMONIC, 'https://goerli.infura.io/v3/22035631f58a401f92c35fc534df3af4', 0),
159 | // network_id: 5,
160 | // chain_id: 5,
161 | // gas: 5500000
162 | // // gasPrice: 10000000000
163 | // }
164 | }
165 | };
--------------------------------------------------------------------------------
/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);
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
231 |
232 | >
233 | );
234 | }
235 | }
236 |
237 | export default withRouter(Navbar);
--------------------------------------------------------------------------------
/src/Contracts/Employee.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.5.0 <0.9.0;
3 |
4 | contract Employee {
5 | address admin;
6 | address employee_address;
7 | string description;
8 | string location;
9 | uint256[] public overallEndorsement;
10 | uint256 endorsecount;
11 | string name;
12 |
13 | constructor(
14 | address _admin,
15 | address _employee_address,
16 | string memory _name,
17 | string memory _description,
18 | string memory _location
19 | ) public {
20 | admin = _admin;
21 | name = _name;
22 | employee_address = _employee_address;
23 | description = _description;
24 | location = _location;
25 | endorsecount = 0;
26 | }
27 |
28 | modifier OnlyEmployee() {
29 | require(msg.sender == employee_address);
30 | _;
31 | }
32 |
33 | function getEmployeeInfo()
34 | public
35 | view
36 | returns (
37 | address,
38 | string memory,
39 | string memory,
40 | string memory,
41 | uint256,
42 | uint256
43 | )
44 | {
45 | return (employee_address, name, description, location, 0, endorsecount);
46 | }
47 |
48 | function editInfo(
49 | string memory _name,
50 | string memory _descrip,
51 | string memory _location
52 | ) public OnlyEmployee {
53 | name = _name;
54 | description = _descrip;
55 | location = _location;
56 | }
57 |
58 | /*********************************************************SKILLS SECTION**********************************************************/
59 |
60 | struct skillInfo {
61 | string name;
62 | uint256 overall_percentage;
63 | string experience;
64 | bool endorsed;
65 | address endorser_address;
66 | string review;
67 | bool visible;
68 | }
69 |
70 | mapping(string => skillInfo) skillmap;
71 | string[] skills;
72 |
73 | function addSkill(string memory _name, string memory _experience)
74 | public
75 | OnlyEmployee
76 | {
77 | skillInfo memory employeeSkillSet;
78 | employeeSkillSet.name = _name;
79 | employeeSkillSet.experience = _experience;
80 | employeeSkillSet.overall_percentage = 0;
81 | employeeSkillSet.endorsed = false;
82 | employeeSkillSet.visible = true;
83 | skillmap[_name] = employeeSkillSet;
84 | skills.push(_name);
85 | }
86 |
87 | function endorseSkill(
88 | string memory _name,
89 | uint256 _overall_percentage,
90 | string memory _review
91 | ) public {
92 | require(skillmap[_name].visible);
93 | skillmap[_name].overall_percentage = _overall_percentage;
94 | overallEndorsement.push(_overall_percentage);
95 | endorsecount = endorsecount + 1;
96 | skillmap[_name].endorsed = true;
97 | skillmap[_name].endorser_address = msg.sender;
98 | skillmap[_name].review = _review;
99 | }
100 |
101 | function getSkillByName(string memory _name)
102 | private
103 | view
104 | returns (
105 | string memory,
106 | uint256,
107 | string memory,
108 | bool,
109 | address,
110 | string memory,
111 | bool
112 | )
113 | {
114 | return (
115 | skillmap[_name].name,
116 | skillmap[_name].overall_percentage,
117 | skillmap[_name].experience,
118 | skillmap[_name].endorsed,
119 | skillmap[_name].endorser_address,
120 | skillmap[_name].review,
121 | skillmap[_name].visible
122 | );
123 | }
124 |
125 | function getSkillCount() public view returns (uint256) {
126 | return skills.length;
127 | }
128 |
129 | function getSkillByIndex(uint256 _index)
130 | public
131 | view
132 | returns (
133 | string memory,
134 | uint256,
135 | string memory,
136 | bool,
137 | address,
138 | string memory,
139 | bool
140 | )
141 | {
142 | return getSkillByName(skills[_index]);
143 | }
144 |
145 | function deleteSkill(string memory _name) public OnlyEmployee {
146 | skillmap[_name].visible = !skillmap[_name].visible;
147 | }
148 |
149 | /*********************************************************CERTIFICATION SECTION**********************************************************/
150 |
151 | struct certificationInfo {
152 | string name;
153 | address organization;
154 | uint256 score;
155 | bool endorsed;
156 | bool visible;
157 | }
158 |
159 | mapping(string => certificationInfo) certificationmap;
160 | string[] certifications;
161 |
162 | function addCertification(
163 | string memory _name,
164 | address _organization,
165 | uint256 _score
166 | ) public OnlyEmployee {
167 | certificationInfo memory newcertificationInfo;
168 | newcertificationInfo.name = _name;
169 | newcertificationInfo.organization = _organization;
170 | newcertificationInfo.score = _score;
171 | newcertificationInfo.endorsed = false;
172 | newcertificationInfo.visible = true;
173 | certificationmap[_name] = newcertificationInfo;
174 | certifications.push(_name);
175 | }
176 |
177 | function endorseCertification(string memory _name) public {
178 | require(msg.sender == certificationmap[_name].organization);
179 | certificationmap[_name].endorsed = true;
180 | }
181 |
182 | function getCertificationByName(string memory _name)
183 | private
184 | view
185 | returns (
186 | string memory,
187 | address,
188 | uint256,
189 | bool,
190 | bool
191 | )
192 | {
193 | return (
194 | certificationmap[_name].name,
195 | certificationmap[_name].organization,
196 | certificationmap[_name].score,
197 | certificationmap[_name].endorsed,
198 | certificationmap[_name].visible
199 | );
200 | }
201 |
202 | function getCertificationCount() public view returns (uint256) {
203 | return certifications.length;
204 | }
205 |
206 | function getCertificationByIndex(uint256 _index)
207 | public
208 | view
209 | returns (
210 | string memory,
211 | address,
212 | uint256,
213 | bool,
214 | bool
215 | )
216 | {
217 | return getCertificationByName(certifications[_index]);
218 | }
219 |
220 | function deleteCertification(string memory _name) public OnlyEmployee {
221 | certificationmap[_name].visible = !certificationmap[_name].visible;
222 | }
223 |
224 | /********************************************************************Work Experience Section********************************************************************/
225 |
226 | struct workexpInfo {
227 | string role;
228 | address organization;
229 | string startdate;
230 | string enddate;
231 | bool endorsed;
232 | string description;
233 | bool visible;
234 | }
235 |
236 | mapping(address => workexpInfo) workexpmap;
237 | address[] workexps;
238 |
239 | function addWorkExp(
240 | string memory _role,
241 | address _organization,
242 | string memory _startdate,
243 | string memory _enddate,
244 | string memory _description
245 | ) public OnlyEmployee {
246 | workexpInfo memory newworkexp;
247 | newworkexp.role = _role;
248 | newworkexp.organization = _organization;
249 | newworkexp.startdate = _startdate;
250 | newworkexp.enddate = _enddate;
251 | newworkexp.endorsed = false;
252 | newworkexp.visible = true;
253 | newworkexp.description = _description;
254 | workexpmap[_organization] = newworkexp;
255 | workexps.push(_organization);
256 | }
257 |
258 | function endorseWorkExp() public {
259 | require(workexpmap[msg.sender].organization != address(0x0));
260 | workexpmap[msg.sender].endorsed = true;
261 | }
262 |
263 | function getWorkExpByAddress(address _organization)
264 | private
265 | view
266 | returns (
267 | string memory,
268 | address,
269 | string memory,
270 | string memory,
271 | bool,
272 | string memory,
273 | bool
274 | )
275 | {
276 | return (
277 | workexpmap[_organization].role,
278 | workexpmap[_organization].organization,
279 | workexpmap[_organization].startdate,
280 | workexpmap[_organization].enddate,
281 | workexpmap[_organization].endorsed,
282 | workexpmap[_organization].description,
283 | workexpmap[_organization].visible
284 | );
285 | }
286 |
287 | function getWorkExpCount() public view returns (uint256) {
288 | return workexps.length;
289 | }
290 |
291 | function getWorkExpByIndex(uint256 _index)
292 | public
293 | view
294 | returns (
295 | string memory,
296 | address,
297 | string memory,
298 | string memory,
299 | bool,
300 | string memory,
301 | bool
302 | )
303 | {
304 | return getWorkExpByAddress(workexps[_index]);
305 | }
306 |
307 | function deleteWorkExp(address org) public OnlyEmployee {
308 | workexpmap[org].visible = false;
309 | }
310 |
311 | /********************************************************************Education Section********************************************************************/
312 |
313 | struct educationInfo {
314 | address institute;
315 | string startdate;
316 | string enddate;
317 | bool endorsed;
318 | string description;
319 | }
320 |
321 | mapping(address => educationInfo) educationmap;
322 | address[] educations;
323 |
324 | function addEducation(
325 | address _institute,
326 | string memory _startdate,
327 | string memory _enddate,
328 | string memory _description
329 | ) public OnlyEmployee {
330 | educationInfo memory newEducation;
331 | newEducation.institute = _institute;
332 | newEducation.startdate = _startdate;
333 | newEducation.enddate = _enddate;
334 | newEducation.endorsed = false;
335 | newEducation.description = _description;
336 | educationmap[_institute] = newEducation;
337 | educations.push(_institute);
338 | }
339 |
340 | function endorseEducation() public {
341 | require(educationmap[msg.sender].institute != address(0x0));
342 | educationmap[msg.sender].endorsed = true;
343 | }
344 |
345 | function getEducationByAddress(address _institute)
346 | private
347 | view
348 | returns (
349 | address,
350 | string memory,
351 | string memory,
352 | bool,
353 | string memory
354 | )
355 | {
356 | return (
357 | educationmap[_institute].institute,
358 | educationmap[_institute].startdate,
359 | educationmap[_institute].enddate,
360 | educationmap[_institute].endorsed,
361 | educationmap[_institute].description
362 | );
363 | }
364 |
365 | function getEducationCount() public view returns (uint256) {
366 | return educations.length;
367 | }
368 |
369 | function getEducationByIndex(uint256 _index)
370 | public
371 | view
372 | returns (
373 | address,
374 | string memory,
375 | string memory,
376 | bool,
377 | string memory
378 | )
379 | {
380 | return getEducationByAddress(educations[_index]);
381 | }
382 | }
--------------------------------------------------------------------------------
/src/components/EmployeeCard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { withRouter } from "react-router-dom";
3 | import { Card } from "semantic-ui-react";
4 | import Employee from "../abis/Employee.json";
5 | import "./EmployeeCard.css";
6 | import LoadComp from "./LoadComp";
7 |
8 | class EmployeeCard extends Component {
9 | state = {
10 | employeedata: {},
11 | skills: [],
12 | certifications: [],
13 | workExps: [],
14 | educations: [],
15 | colour: ["#b6e498", "#61dafb", "#764abc", "#83cd29", "#00d1b2"],
16 | readmore: false,
17 | loadcomp: false,
18 | };
19 |
20 | componentDidMount = async () => {
21 | const web3 = window.web3;
22 | const EmployeeContract = await new web3.eth.Contract(
23 | Employee.abi,
24 | this.props.employeeContractAddress
25 | );
26 | this.getSkills(EmployeeContract);
27 | this.getCertifications(EmployeeContract);
28 | this.getWorkExp(EmployeeContract);
29 | this.getEducation(EmployeeContract);
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 });
42 | };
43 |
44 | getSkills = async (EmployeeContract) => {
45 | const skillCount = await EmployeeContract?.methods?.getSkillCount().call();
46 | const skills = await Promise.all(
47 | Array(parseInt(skillCount))
48 | .fill()
49 | .map((ele, index) =>
50 | EmployeeContract?.methods?.getSkillByIndex(index).call()
51 | )
52 | );
53 |
54 | var newskills = [];
55 | skills.forEach((certi) => {
56 | newskills.push({
57 | name: certi[0],
58 | overall_percentage: certi[1],
59 | experience: certi[2],
60 | endorsed: certi[3],
61 | endorser_address: certi[4],
62 | review: certi[5],
63 | });
64 | return;
65 | });
66 |
67 | this.setState({ skills: newskills });
68 | };
69 |
70 | getCertifications = async (EmployeeContract) => {
71 | const certiCount = await EmployeeContract?.methods
72 | ?.getCertificationCount()
73 | .call();
74 | const certifications = await Promise.all(
75 | Array(parseInt(certiCount))
76 | .fill()
77 | .map((ele, index) =>
78 | EmployeeContract?.methods?.getCertificationByIndex(index).call()
79 | )
80 | );
81 | var newcertifications = [];
82 | certifications.forEach((certi) => {
83 | newcertifications.push({
84 | name: certi[0],
85 | organization: certi[1],
86 | score: certi[2],
87 | endorsed: certi[3],
88 | });
89 | return;
90 | });
91 | this.setState({ certifications: newcertifications });
92 | };
93 |
94 | getWorkExp = async (EmployeeContract) => {
95 | const workExpCount = await EmployeeContract?.methods
96 | ?.getWorkExpCount()
97 | .call();
98 | const workExps = await Promise.all(
99 | Array(parseInt(workExpCount))
100 | .fill()
101 | .map((ele, index) =>
102 | EmployeeContract?.methods?.getWorkExpByIndex(index).call()
103 | )
104 | );
105 |
106 | var newworkExps = [];
107 | workExps.forEach((work) => {
108 | newworkExps.push({
109 | role: work[0],
110 | organization: work[1],
111 | startdate: work[2],
112 | enddate: work[3],
113 | endorsed: work[4],
114 | description: work[5],
115 | });
116 | return;
117 | });
118 |
119 | this.setState({ workExps: newworkExps });
120 | };
121 |
122 | getEducation = async (EmployeeContract) => {
123 | const educationCount = await EmployeeContract?.methods
124 | ?.getEducationCount()
125 | .call();
126 | const educations = await Promise.all(
127 | Array(parseInt(educationCount))
128 | .fill()
129 | .map((ele, index) =>
130 | EmployeeContract?.methods?.getEducationByIndex(index).call()
131 | )
132 | );
133 | var neweducation = [];
134 | educations.forEach((certi) => {
135 | neweducation.push({
136 | institute: certi[0],
137 | startdate: certi[1],
138 | enddate: certi[2],
139 | endorsed: certi[3],
140 | description: certi[4],
141 | });
142 | return;
143 | });
144 | this.setState({ educations: neweducation });
145 | };
146 |
147 | toEmployee = () => {
148 | this.props.history.push(
149 | `/getemployee/${this.props.employeeContractAddress}`
150 | );
151 | };
152 |
153 | render() {
154 | return this.state.loadcomp ? (
155 |
156 | ) : (
157 |
158 |
159 |
160 | {this.state.employeedata?.name}
161 | {this.state.employeedata.ethAddress}
162 |
163 |
164 |
165 |
166 | Location :
167 |
168 | {this.state.employeedata?.location}
169 |
170 |
171 |
172 |
173 |
174 |
Description :
175 |
176 | {this.state.employeedata?.description}
177 |
178 |
179 |
180 |
181 |
Skills:
182 |
183 | {this.state.skills?.map((skill, index) => (
184 |
193 | ))}
194 |
195 |
196 |
197 | {this.state.readmore ? (
198 |
199 |
200 |
Education:
201 |
202 | {this.state.educations?.map((education, index) => (
203 |
207 |
208 |
{education.description}
209 |
{education.institute}
210 |
211 |
212 |
213 |
214 | {education.startdate} - {education.enddate}
215 |
216 |
217 |
223 | {education.endorsed ? "Endorsed" : "Not Yet Endorsed"}
224 |
225 |
226 |
227 | ))}
228 |
229 |
230 |
231 |
232 |
Certifications:
233 |
234 | {this.state.certifications?.map((certification, index) => (
235 |
239 |
240 |
{certification.name}
241 |
{certification.organization}
242 |
243 |
244 |
245 | Score: {certification.score}
246 |
247 |
255 | {certification.endorsed
256 | ? "Endorsed"
257 | : "Not Yet Endorsed"}
258 |
259 |
260 |
261 | ))}
262 |
263 |
264 |
265 |
266 |
Work Experience:
267 |
268 | {this.state.workExps?.map((work, index) => (
269 |
273 |
274 |
{work.role}
275 |
{work.organization}
276 |
277 |
278 |
279 |
280 |
281 | {work.startdate} - {work.enddate}
282 |
283 |
284 |
285 |
291 | {work.endorsed ? "Endorsed" : "Not Yet Endorsed"}
292 |
293 |
294 |
295 | ))}
296 |
297 |
298 |
299 |
this.setState({ readmore: false })}
302 | >
303 |
Hide
304 |
305 |
306 | ) : (
307 | this.setState({ readmore: true })}
310 | >
311 |
...Read More
312 |
313 | )}
314 |
315 |
316 | );
317 | }
318 | }
319 |
320 | export default withRouter(EmployeeCard);
--------------------------------------------------------------------------------