├── .gitignore ├── LICENSE ├── OCN.pdf ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── img │ └── logo.svg ├── index.html └── manifest.json └── src ├── App.css ├── App.js ├── App.test.js ├── Components ├── HeaderComponents │ ├── header.css │ ├── header.js │ └── logo.svg └── Pages │ ├── Accounts │ ├── accounts.css │ └── accounts.js │ ├── Register │ ├── register.css │ └── register.js │ └── View │ ├── view.css │ └── view.js ├── OpenComplainNetwork.json ├── img └── logo.svg ├── index.css ├── index.js ├── registerServiceWorker.js └── truffle-contract ├── contracts ├── Migrations.sol └── OpenComplainNetwork.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── truffle-config.js └── truffle.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Abhishek Upperwal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OCN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upperwal/OpenComplaintNetwork/1fd7317b3948fa710fdbd6f2936b82ae761ceb4a/OCN.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Open Complain Network (OCN) 2 | 3 | 4 | [![Open Complain Network](https://img.youtube.com/vi/Rw6KoLND9tc/0.jpg)](https://youtu.be/Rw6KoLND9tc) 5 | 6 | 7 | Platform used: 8 | 1. Nodejs 9 | 2. Truffle for development 10 | 11 | How to Run: 12 | 1. Starting Truffle Develop 13 | - cd src/truffle-contract 14 | - truffle develop 15 | - compile 16 | - migrate 17 | 18 | 2. Starting lite server : in project root 19 | - npm start 20 | 21 | ### Introduction 22 | 23 | The Open Complaint Network is a decentralized system for lodging complaints, both civil and criminal onto a network that uses block chain, engaging citizens and police personnel. 24 | 25 | In case of a compaint, the citizen ought to register the complaint online that will reach all police accounts and the citizen shall not have to worry about jurisdictional issues, and neither will the policemen. The network will also help solve problems that transcend jurisdictional territories faster and with easy communication. The network is devised such that the citizens hold accounts through which they can file complaints, each police station has an account across the country and the administrator holds access and control. 26 | 27 | The network allows for all complaints to be lodged, major or minor. A complaint automatically generates a registration, which the citizen can track over time and check the progress. 28 | 29 | The access to all citizens allows for peer-to-peer helping network to file complaints and help each other solve problems. For eg. If A looses her Voter ID Card, and B reads the complaint on the blockchain and finds the card near him. A may choose to offer a reward for the same which in case of successful finding and transfer f lost items, shall be transferred to B's account through the same network. This is an innovative way to engage the citizens in helping one another and also helps take the pressure off the police by de-centralizing the process and allowing for greater vigilantism among the people themselves. This in the long run, shall help people be more aware of their surroundings, help each other and participate better in their societies. 30 | 31 | [Block Diagram](https://github.com/upperwal/OpenComplainNetwork/blob/master/OCN.pdf) 32 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "network-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "bootstrap": "^3.3.7", 7 | "jquery": "^3.2.1", 8 | "react": "^16.1.0", 9 | "react-dom": "^16.1.0", 10 | "react-router-dom": "^4.2.2", 11 | "react-scripts": "1.0.17", 12 | "web3": "^1.2.9" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upperwal/OpenComplaintNetwork/1fd7317b3948fa710fdbd6f2936b82ae761ceb4a/public/favicon.ico -------------------------------------------------------------------------------- /public/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 | 27 | 28 | 31 |
32 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upperwal/OpenComplaintNetwork/1fd7317b3948fa710fdbd6f2936b82ae761ceb4a/src/App.css -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | BrowserRouter as Router, 4 | Route, 5 | Link 6 | } from 'react-router-dom' 7 | 8 | 9 | import './App.css'; 10 | 11 | import Header from './Components/HeaderComponents/header' 12 | import Register from './Components/Pages/Register/register' 13 | import View from './Components/Pages/View/view' 14 | import Accounts from './Components/Pages/Accounts/accounts' 15 | 16 | import Web3 from 'web3' 17 | 18 | import ContractsABIJSON from './truffle-contract/build/contracts/OpenComplainNetwork.json' 19 | 20 | console.log(ContractsABIJSON) 21 | 22 | window.abi = ContractsABIJSON.abi 23 | window.add = ContractsABIJSON.networks['5777'].address 24 | 25 | class App extends Component { 26 | 27 | constructor(props) { 28 | super(props) 29 | this.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:9545")); 30 | window._web3 = this.web3; 31 | 32 | this.complainContract = new this.web3.eth.Contract(window.abi, window.add, { 33 | from: '0x627306090abab3a6e1400e9345bc60c78a8bef57', 34 | gasPrice: '20000000000', 35 | gas: 2000000 36 | }) 37 | 38 | console.log(JSON) 39 | 40 | window._contact = this.complainContract 41 | } 42 | 43 | render() { 44 | return ( 45 | 46 |
47 |
48 | 49 | ( )} /> 50 | ( )} /> 51 | 52 | ( )} /> 53 | 54 |
55 |
56 | ); 57 | } 58 | } 59 | 60 | export default App; 61 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/Components/HeaderComponents/header.css: -------------------------------------------------------------------------------- 1 | .App { 2 | 3 | } 4 | 5 | .App-header { 6 | background-color: #2b2b2b; 7 | color: white; 8 | padding: 6px 40px; 9 | width: 100%; 10 | } 11 | 12 | .small-header { 13 | width: 90%; 14 | margin: auto; 15 | } 16 | 17 | .small-header > h1 { 18 | display: inline; 19 | margin-left: 30px; 20 | } 21 | 22 | .small-header > .links { 23 | margin-left: 90px; 24 | display: inline-block; 25 | } 26 | 27 | .small-header > .links > a { 28 | color: white; 29 | background-color: #444; 30 | padding: 20px 80px; 31 | margin: 0px 10px; 32 | border-radius: 8px; 33 | font-size: 1.3em; 34 | } 35 | 36 | .small-header > .links > a:hover { 37 | background-color: #333; 38 | } 39 | 40 | .App-title { 41 | font-size: 2.3em; 42 | } 43 | 44 | .App-intro { 45 | font-size: large; 46 | } 47 | 48 | @keyframes App-logo-spin { 49 | from { transform: rotate(0deg); } 50 | to { transform: rotate(360deg); } 51 | } 52 | -------------------------------------------------------------------------------- /src/Components/HeaderComponents/header.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | Link 4 | } from 'react-router-dom' 5 | 6 | import './header.css' 7 | 8 | import logo from './logo.svg'; 9 | import logo2 from '../../img/logo.svg' 10 | 11 | class Header extends Component { 12 | render() { 13 | return ( 14 |
15 | 16 | 17 |
18 |
19 | 20 |

Open Complain Network

21 |
22 | Register 23 | View 24 |
25 |
26 |
27 | 28 | 29 |
30 | ); 31 | } 32 | } 33 | 34 | export default Header; 35 | 36 | -------------------------------------------------------------------------------- /src/Components/HeaderComponents/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Components/Pages/Accounts/accounts.css: -------------------------------------------------------------------------------- 1 | .accounts-class { 2 | text-align: left; 3 | width: 80%; 4 | margin: auto; 5 | margin-top: 40px; 6 | } -------------------------------------------------------------------------------- /src/Components/Pages/Accounts/accounts.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import './accounts.css' 4 | 5 | class Accounts extends Component { 6 | 7 | constructor(props) { 8 | super(props) 9 | this.complainContract = props.contractObject 10 | this.web3 = props.web3Obj 11 | 12 | this.state = { 13 | table: '' 14 | } 15 | 16 | this.globalPromise = [] 17 | this.accounts = [] 18 | this.balances = [] 19 | } 20 | 21 | componentWillMount() { 22 | this.getAllAccounts() 23 | console.log('Got Accounts') 24 | this.getBalances() 25 | 26 | } 27 | getAllAccounts() { 28 | var context = this 29 | this.web3.eth.getAccounts().then(function(res) { 30 | context.accounts = res 31 | console.log(context.accounts) 32 | }) 33 | } 34 | 35 | getBalances() { 36 | console.log('Inside') 37 | console.log(this.accounts) 38 | var context = this 39 | new Promise(function(resolve, reject) { 40 | var pro = [] 41 | for(var i = 0; i {resolve(e)}).catch((e) => {reject(e)}) 51 | }).then(console.log) 52 | } 53 | 54 | 55 | 56 | render() { 57 | return( 58 | 59 |
60 |
61 |
All accounts currently in your wallet
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {this.state.table} 77 | 78 | 79 | 80 | 81 |
#NameLocationDescriptionTypeRewardStatusAction
82 |
83 |
84 | 85 | ); 86 | } 87 | 88 | } 89 | 90 | export default Accounts -------------------------------------------------------------------------------- /src/Components/Pages/Register/register.css: -------------------------------------------------------------------------------- 1 | #register-class { 2 | width: 70%; 3 | margin: auto; 4 | margin-top: 40px; 5 | } 6 | 7 | .notify { 8 | position: fixed; 9 | bottom: 10px; 10 | left: 10px; 11 | } 12 | 13 | #complain-submit { 14 | background-color: #f7f7f7; 15 | } -------------------------------------------------------------------------------- /src/Components/Pages/Register/register.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import $ from 'jquery'; 4 | 5 | import './register.css' 6 | 7 | class Register extends Component { 8 | constructor(props) { 9 | super(props) 10 | this.complainContract = props.contractObject 11 | this.web3 = props.web3Obj 12 | console.log('Class: Register') 13 | console.log(this.complainContract) 14 | 15 | this.formPreventDefault = this.formPreventDefault.bind(this); 16 | this.updateUser = this.updateUser.bind(this); 17 | this.register = this.register.bind(this); 18 | 19 | this.state = { 20 | notify: '', 21 | notiClass: 'success' 22 | } 23 | 24 | this.accounts = [] 25 | 26 | this.getAccounts() 27 | 28 | this.selectUser = 0; 29 | 30 | } 31 | 32 | getAccounts() { 33 | var context = this 34 | this.web3.eth.getAccounts().then(function(res) { 35 | context.accounts = res 36 | console.log(context.accounts) 37 | }) 38 | } 39 | 40 | formPreventDefault(e) { 41 | alert('here'); 42 | e.preventDefault(); 43 | } 44 | 45 | register(e) { 46 | 47 | var latdata = 0, longdata = 0 48 | function getLocation() { 49 | if (navigator.geolocation) { 50 | navigator.geolocation.getCurrentPosition(showPosition); 51 | } else { 52 | console.log("Geolocation is not supported by this browser."); 53 | } 54 | } 55 | function showPosition(position) { 56 | latdata = parseInt(position.coords.latitude * 1e12) 57 | longdata = parseInt(position.coords.longitude * 1e12) 58 | } 59 | 60 | getLocation() 61 | 62 | 63 | e.preventDefault(); 64 | 65 | var data = [] 66 | data.push($('#input-name').val().replace(new RegExp(',', 'g'), '#')) 67 | data.push($('#input-address').val().replace(new RegExp(',', 'g'), '#')) 68 | data.push($('#input-desc').val().replace(new RegExp(',', 'g'), '#')) 69 | console.log(data) 70 | data = data.toString().replace(new RegExp(',', 'g'), '?').replace(new RegExp('#', 'g'), ','); 71 | console.log(data) 72 | 73 | var catdata = $('#type').val() 74 | 75 | var reward = parseInt($('#input-reward').val()) * 1e9 76 | 77 | /*let objJsonStr = JSON.stringify(data); 78 | let objJsonB64 = new Buffer(objJsonStr).toString("base64");*/ 79 | 80 | var part = btoa(data) 81 | 82 | var context = this 83 | 84 | this.complainContract.methods.registerComplain(part, longdata, latdata, catdata).send({from: this.accounts[this.selectUser], value: reward}) 85 | .then(function(response) { 86 | context.complainContract.methods.registerComplain(part, longdata, latdata, catdata).call().then(function(cid) { 87 | console.log('CID: ' + cid) 88 | context.setState({notify: 'Complain Registered.', notiClass: 'success'}) 89 | //$('#notify').html("Complain Registered with ID: " + cid) 90 | }); 91 | 92 | console.log(response) 93 | console.log('End of Response') 94 | }).catch(function(err) { 95 | context.setState({notify: 'Error: Complain not Registered.', notiClass: 'danger'}) 96 | console.log('Error: Message: ' + err.message); 97 | }); 98 | 99 | 100 | } 101 | 102 | /*componentWillMount() { 103 | 104 | 105 | 106 | 107 | console.log(this.complainContract) 108 | 109 | 110 | }*/ 111 | 112 | 113 | 114 | updateUser(e) { 115 | this.selectUser = e.target.value 116 | 117 | this.setState({gg: 'some'}) 118 | 119 | /*if(this.selectUser == 0) { 120 | 121 | this.setState({secondBtn: 'invisible', isSuperUser: 'visible',isCitizen: 'invisible', classFirst: 'glyphicon glyphicon-plus', classSecond: 'hidden', tipFirst: 'Assign new Police accounts', tipSecond: 'Empty'}, function() { 122 | this.setState({table: this.renderTable()}) 123 | }) 124 | } 125 | else if(this.selectUser == 1) { 126 | this.setState({secondBtn: 'visible', isSuperUser: 'invisible',isCitizen: 'invisible', classFirst: 'glyphicon glyphicon-arrow-up', classSecond: 'glyphicon glyphicon-arrow-down', tipFirst: 'Upgrade complain status', tipSecond: 'Downgrade complain status'}, function() { 127 | this.setState({table: this.renderTable()}) 128 | }) 129 | } 130 | else if(this.selectUser == 2 || this.selectUser == 3) { 131 | this.setState({secondBtn: 'visible', isSuperUser: 'invisible',isCitizen: 'visible', classFirst: 'glyphicon glyphicon-flash', classSecond: 'glyphicon glyphicon-send', tipFirst: 'Fund a complain', tipSecond: 'Report a Solution'}, function() { 132 | this.setState({table: this.renderTable()}) 133 | }) 134 | }*/ 135 | 136 | 137 | //console.log(this.state.classFirst) 138 | } 139 | 140 | render() { 141 | return ( 142 |
143 |

Select a User to perform the following action.

144 | 150 |

Account No: {this.accounts[this.selectUser]}

151 |
152 |
153 |
154 |

155 | To register a complain please fill the following form. 156 |

157 |
158 |
159 | 160 |
161 | 162 |
163 |
164 |
165 | 166 |
167 | 168 |
169 |
170 |
171 | 172 |
173 | 174 |
175 |
176 |
177 | 178 |
179 | 180 |
181 |
182 |
183 | 184 |
185 | 189 |
190 |
191 |
192 |
193 | 194 |
195 |
196 |
197 | {this.state.notify} 198 |
199 |
200 |
201 | ); 202 | } 203 | } 204 | 205 | export default Register; 206 | 207 | -------------------------------------------------------------------------------- /src/Components/Pages/View/view.css: -------------------------------------------------------------------------------- 1 | .view-class { 2 | text-align: left; 3 | width: 80%; 4 | margin: auto; 5 | margin-top: 40px; 6 | } 7 | 8 | .label { 9 | cursor: pointer; 10 | margin-bottom: 5px; 11 | } 12 | 13 | h5 { 14 | display: inline; 15 | margin-left: 6px; 16 | margin-right: 20px; 17 | } 18 | 19 | .notify { 20 | position: fixed; 21 | bottom: 10px; 22 | left: 10px; 23 | } 24 | 25 | .police-accounts { 26 | margin-top: 30px; 27 | } 28 | h3 { 29 | margin: 20px 0px; 30 | } 31 | .police-accounts input { 32 | margin: 20px 0px; 33 | } 34 | .police-accounts button { 35 | background-color: #f7f7f7; 36 | margin-bottom: 20px; 37 | } 38 | .police-accounts .label { 39 | font-size: 0.6em; 40 | } 41 | .label { 42 | margin: 0px 2px; 43 | } 44 | .invisible { 45 | display: none; 46 | } 47 | .visible { 48 | display: block-inherit; 49 | } 50 | .Accepted { 51 | text-align: center; 52 | border-radius: 6px; 53 | padding: 3px; 54 | color: #fff; 55 | background-color: #3337f7; 56 | } 57 | .Resolved { 58 | text-align: center; 59 | border-radius: 6px; 60 | padding: 3px; 61 | color: #fff; 62 | background-color: #139019; 63 | } 64 | .Pending { 65 | text-align: center; 66 | border-radius: 6px; 67 | padding: 3px; 68 | color: #fff; 69 | background-color: #a91343; 70 | } 71 | 72 | .Proposed { 73 | text-align: center; 74 | border-radius: 6px; 75 | padding: 3px; 76 | color: #fff; 77 | background-color: #cf2f10; 78 | } -------------------------------------------------------------------------------- /src/Components/Pages/View/view.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import './view.css' 4 | 5 | 6 | import $ from 'jquery' 7 | 8 | class View extends Component { 9 | 10 | constructor(props) { 11 | super(props) 12 | this.complainContract = props.contractObject 13 | this.web3 = props.web3Obj 14 | console.log('Class: View') 15 | 16 | this.updateUser = this.updateUser.bind(this); 17 | this.renderTable = this.renderTable.bind(this); 18 | 19 | this.actionFirstButton = this.actionFirstButton.bind(this); 20 | this.actionSecondButton = this.actionSecondButton.bind(this); 21 | this.actionThirdButton = this.actionThirdButton.bind(this); 22 | this.actionFourthButton = this.actionFourthButton.bind(this); 23 | this.sendTransPolList = this.sendTransPolList.bind(this); 24 | this.updatePoliceList = this.updatePoliceList.bind(this); 25 | this.actionPolFund = this.actionPolFund.bind(this); 26 | 27 | this.state = { 28 | table: [], 29 | classFirst: 'glyphicon glyphicon-plus', 30 | classSecond: 'hidden', 31 | tipFirst: 'Assign new Police accounts', 32 | tipSecond: 'Empty', 33 | isSuperUser: 'visible', 34 | isCitizen: 'invisible', 35 | secondBtn: 'invisible', 36 | polFund: 'invisible', 37 | polTip: 'Fund this Complain', 38 | notification: '', 39 | notiClass: 'success', 40 | polAcc: [] 41 | } 42 | 43 | this.fetchedComplains = [] 44 | this.promiseEachComplain = [] 45 | this.selectUser = 0 46 | 47 | this.accounts = [] 48 | this.polList = '' 49 | 50 | this.getAccounts() 51 | } 52 | 53 | catType(a) { 54 | console.log('dfdsfsdf'+ a) 55 | if(a==0) 56 | return 'Lost' 57 | else if(a==1) 58 | return 'Theft' 59 | } 60 | 61 | statusType(a) { 62 | if(a == 0) 63 | return 'Pending' 64 | else if(a == 1) 65 | return 'Accepted' 66 | else if(a == 2) 67 | return 'Resolved' 68 | else if(a == 3) 69 | return 'Proposed' 70 | } 71 | 72 | actionFirstButton(e) { 73 | var complain = this.fetchedComplains[e.target.getAttribute('data-index')] 74 | var context = this; 75 | 76 | if(this.selectUser == 1) { 77 | console.log('Complain Status: '+complain.status) 78 | if(complain.status < 2) { 79 | this.complainContract.methods.changeStatus(complain.cid, parseInt(complain.status) + 1).send({from: this.accounts[this.selectUser]}) 80 | .then(function(res) { 81 | console.log(res) 82 | context.setState({notification: 'Complain Status Changed.', notiClass: 'success'}) 83 | context.componentWillMount() 84 | }).catch(function(res) { 85 | context.setState({notification: 'Error: This might not be added as a Police Account', notiClass: 'danger'}) 86 | console.log(res) 87 | }) 88 | } 89 | else { 90 | this.setState({notification: 'Complain Status cant go above "Resolved" or "Proposed"', notiClass: 'danger'}) 91 | } 92 | 93 | } 94 | else if(this.selectUser == 2 || this.selectUser == 3) { 95 | console.log("Fund : "+complain.cid) 96 | if($('#input-reward').val() == '') { 97 | context.setState({notification: 'No Fund Specified. Please enter some amount.', notiClass: 'danger'}) 98 | return 99 | } 100 | var fundValue = parseInt($('#input-reward').val()) * 1e9 101 | this.complainContract.methods.fundComplain(complain.cid).send({from: this.accounts[this.selectUser], value: fundValue}) 102 | .then(function(res) { 103 | console.log(res) 104 | context.setState({notification: 'Complain Funded', notiClass: 'success'}) 105 | context.componentWillMount() 106 | }).catch(() => {context.setState({notification: 'Error Occured: Complain should be Accepted or Proposed', notiClass: 'danger'})}) 107 | } 108 | } 109 | 110 | actionSecondButton(e) { 111 | var complain = this.fetchedComplains[e.target.getAttribute('data-index')] 112 | var context = this; 113 | if(this.selectUser == 1) { 114 | if(complain.status > 0) { 115 | this.complainContract.methods.changeStatus(complain.cid, parseInt(complain.status) - 1).send({from: this.accounts[this.selectUser]}) 116 | .then(function(res) { 117 | console.log(res) 118 | context.setState({notification: 'Status Changed', notiClass: 'success'}) 119 | context.componentWillMount() 120 | }).catch(() => {context.setState({notification: 'Error Dec: This might not be added as a Police Account', notiClass: 'danger'})}) 121 | } 122 | else { 123 | this.setState({notification: 'Complain Status cant go below "Pending"', notiClass: 'danger'}) 124 | } 125 | 126 | } 127 | else if(this.selectUser == 2 || this.selectUser == 3) { 128 | this.complainContract.methods.claimSolution(complain.cid).send({from: this.accounts[this.selectUser]}) 129 | .then(function(res) { 130 | console.log(res) 131 | context.setState({notification: 'Solution Claimed', notiClass: 'success'}) 132 | context.componentWillMount() 133 | }).catch(() => {context.setState({notification: 'Error Occured: You cant propose on your complain or a solution is already proposed.', notiClass: 'danger'})}) 134 | } 135 | } 136 | 137 | actionThirdButton(e) { 138 | var complain = this.fetchedComplains[e.target.getAttribute('data-index')] 139 | var context = this; 140 | this.complainContract.methods.resolve(complain.cid).send({from: this.accounts[this.selectUser]}) 141 | .then(function(res) { 142 | console.log(res) 143 | context.setState({notification: 'Complain resolved and closed. Fund Transfered.', notiClass: 'success'}) 144 | context.componentWillMount() 145 | }).catch(() => {context.setState({notification: 'Error Occured: This might not be your complain.', notiClass: 'danger'})}) 146 | } 147 | 148 | actionFourthButton(e) { 149 | var complain = this.fetchedComplains[e.target.getAttribute('data-index')] 150 | var context = this; 151 | this.complainContract.methods.declineProposal(complain.cid).send({from: this.accounts[this.selectUser]}) 152 | .then(function(res) { 153 | console.log(res) 154 | context.setState({notification: 'Complain Solution declined. Set to Accept Status.', notiClass: 'success'}) 155 | context.componentWillMount() 156 | }).catch(() => {context.setState({notification: 'Error Occured: You might not be the owner of this complain.', notiClass: 'danger'})}) 157 | } 158 | 159 | actionPolFund(e) { 160 | var complain = this.fetchedComplains[e.target.getAttribute('data-index')] 161 | var context = this; 162 | 163 | var fundValue = parseInt($('#input-reward').val()) * 1e9 164 | 165 | this.complainContract.methods.fundComplain(complain.cid).send({from: this.accounts[this.selectUser], value: fundValue}) 166 | .then(function(res) { 167 | console.log(res) 168 | context.setState({notification: 'Complain Funded'}) 169 | context.componentWillMount() 170 | }).catch(() => {context.setState({notification: 'Error Occured', notiClass: 'danger'})}) 171 | } 172 | 173 | getAccounts() { 174 | var context = this 175 | this.web3.eth.getAccounts().then(function(res) { 176 | context.accounts = res 177 | console.log(context.accounts) 178 | }) 179 | } 180 | 181 | 182 | 183 | componentWillMount() { 184 | this.fetchedComplains = [] 185 | this.promiseEachComplain = [] 186 | this.fetchFreshData() 187 | 188 | var context = this 189 | 190 | Promise.all(this.promiseEachComplain).then(function() { 191 | context.setState({table: context.renderTable()}) 192 | }) 193 | 194 | } 195 | 196 | fetchFreshData() { 197 | var noOfComplainsFetch = 20 198 | 199 | var context = this 200 | 201 | var majorPromise = new Promise(function(resolve, reject) { 202 | for(var i=0; i{fetchData.cid} 274 | var _td1 = {details[0]} 275 | var _td2 = {details[1]} 276 | var _td3 = {details[2]} 277 | var _td4 = {context.catType(fetchData.cat)} 278 | var _td5 = ₹ {(fetchData.reward/1e9).toFixed(2)} 279 | var _td6 =

{context.statusType(fetchData.status)}

280 | var _td7 = 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | //var t = 300 | 301 | //var u = React.cloneElement(t) 302 | //var _td = Hello 303 | var _tr = {_th}{_td1}{_td2}{_td3}{_td4}{_td5}{_td6}{_td7} 304 | 305 | reactTableRows.push(_tr) 306 | 307 | 308 | } 309 | var reactTBody = React.createElement('tbody', {'id': 'table-body'}, reactTableRows) 310 | 311 | console.log(reactTBody) 312 | return reactTBody 313 | //context.setState({table: pp}) 314 | //p.push(_tr) 315 | } 316 | 317 | updatePoliceList(e) { 318 | this.polList = e.target.value; 319 | console.log(this.polList) 320 | } 321 | 322 | sendTransPolList() { 323 | var accList = this.polList.split(',') 324 | console.log(accList) 325 | var context = this; 326 | this.complainContract.methods.modifyPoliceAccounts(accList).send({from: this.accounts[this.selectUser]}) 327 | .then(function(res) { 328 | console.log(res) 329 | context.setState({notification: 'Police Acoounts Modified', notiClass: 'success'}) 330 | //context.checkPolAccount() 331 | 332 | 333 | }).catch(() => {context.setState({notification: 'Error Occured while modifying Police Accounts', notiClass: 'danger'})}) 334 | } 335 | 336 | checkPolAccount() { 337 | var context = this 338 | var yy = [] 339 | var dep = [] 340 | for(var i =0; i 364 | 370 |
371 | 372 |
373 |
374 |
Complain fetched from Blockchain
375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | {this.state.table} 390 | 391 | 392 | 393 | 394 |
#NameLocationDescriptionTypeRewardStatusAction
395 |
396 | 397 |
398 | 399 | 400 | 401 |
{this.state.tipFirst}
402 | 403 | 404 | 405 |
{this.state.tipSecond}
406 | 407 | 408 | 409 | 410 |
Close/Resolve Complain [Funds will be awarded or sent back]
411 | 412 | 413 | 414 |
Decline Proposal
415 | 416 | 417 | 418 |
{this.state.polTip}
419 |
420 | 421 |
422 |
423 |
424 |
425 |

Update Police Accounts

426 | 427 | 428 |
Police account is not added to the list by default. Complain status change will fail if not added.
429 | 430 |
431 |
432 |

Account Addresses

433 |
434 | 435 |
    436 |
  • SuperUser : {this.accounts[0]}
  • 437 |
  • Police : {this.accounts[1]}
  • 438 |
  • Citizen1 : {this.accounts[2]}
  • 439 |
  • Citizen2 : {this.accounts[3]}
  • 440 |
441 |
442 | 443 | 444 |
445 |
446 | 447 | 448 | 449 | 450 |
451 | 452 | {this.state.notification} 453 |
454 | 455 | ); 456 | } 457 | 458 | 459 | } 460 | 461 | export default View; 462 | 463 | -------------------------------------------------------------------------------- /src/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | padding-bottom: 20px; 6 | } 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; 5 | import './index.css'; 6 | 7 | import App from './App'; 8 | import registerServiceWorker from './registerServiceWorker'; 9 | 10 | ReactDOM.render(, document.getElementById('root')); 11 | registerServiceWorker(); 12 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | } else { 39 | // Is not local host. Just register service worker 40 | registerValidSW(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/truffle-contract/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.17; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() public { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/truffle-contract/contracts/OpenComplainNetwork.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.17; 2 | 3 | contract OpenComplainNetwork { 4 | enum Status { Pending, Accepted, Resolved, Proposed } 5 | 6 | struct Complain { 7 | /*bytes[50] _name; 8 | bytes[50] _address; 9 | bytes[50] _desc; 10 | bytes[50] _location; 11 | bytes[50] _category;*/ 12 | uint _lat; 13 | uint _long; 14 | uint _category; 15 | string _data; 16 | address _personID; 17 | Status _status; 18 | uint _reward; 19 | address _policeAssigned; 20 | address[] _contributors; 21 | uint[] _contAmount; 22 | } 23 | 24 | uint private complainCounter; 25 | mapping(uint => Complain) private complainMap; 26 | mapping(address => bool) private policeAccounts; 27 | address private superuser; 28 | mapping(uint => address) private complainSolver; 29 | 30 | function OpenComplainNetwork() public { 31 | superuser = msg.sender; 32 | complainCounter = 0; 33 | } 34 | 35 | modifier superuserAccess() { 36 | require(msg.sender == superuser); 37 | _; 38 | } 39 | 40 | modifier policeAccess { 41 | require(policeAccounts[msg.sender] == true); 42 | _; 43 | } 44 | 45 | modifier complainOwnerAccess(uint cid) { 46 | require(msg.sender == complainMap[cid]._personID); 47 | _; 48 | } 49 | 50 | modifier complainOwnOrPoliceAccess(uint cid) { 51 | require(policeAccounts[msg.sender] == true || msg.sender == complainMap[cid]._personID); 52 | _; 53 | } 54 | 55 | function registerComplain(string data, uint long, uint lat, uint cat) public payable returns(uint) { 56 | complainMap[complainCounter]._long = long; 57 | complainMap[complainCounter]._lat = lat; 58 | complainMap[complainCounter]._category = cat; 59 | complainMap[complainCounter]._data = data; 60 | complainMap[complainCounter]._personID = msg.sender; 61 | complainMap[complainCounter]._status = Status.Pending; 62 | complainMap[complainCounter]._reward = msg.value; 63 | 64 | if(msg.value > 0) { 65 | complainMap[complainCounter]._contributors.push(msg.sender); 66 | complainMap[complainCounter]._contAmount.push(msg.value); 67 | } 68 | /*for(uint i=0; i= Status.Pending)); 82 | complainMap[cid]._status = sta; 83 | 84 | // What if a person solves the problem and then the police 85 | // updates the status to resolved. complainSolver[cid] = 'Police' 86 | // no funds to the Original Solver. 87 | if(sta == Status.Resolved) { 88 | complainSolver[cid] = msg.sender; 89 | } 90 | } 91 | 92 | // Even though Police can resolve and close the complain. 93 | // Complainee would be responsible for transfering the funds, if any. 94 | function resolve(uint cid) public complainOwnerAccess(cid) { 95 | complainMap[cid]._status = Status.Resolved; 96 | 97 | transferFundOnResolve(cid); 98 | } 99 | 100 | function declineProposal(uint cid) public complainOwnerAccess(cid) { 101 | require( complainMap[cid]._status == Status.Proposed ); 102 | complainMap[cid]._status = Status.Accepted; 103 | 104 | complainSolver[cid] = 0; 105 | } 106 | 107 | // If someone other than police solved the complain transfer funds to solver. 108 | // Otherwise send them back to the contributors. 109 | function transferFundOnResolve(uint cid) private { 110 | // Could also be used: complainMap[cid]._status == Status.Resolved && 111 | if(complainMap[cid]._reward > 0) { 112 | if(policeAccounts[complainSolver[cid]] != true) { 113 | complainSolver[cid].transfer( complainMap[cid]._reward ); 114 | complainMap[cid]._reward = 0; 115 | } 116 | else { 117 | for(uint i=0; i 3 | // to customize your Truffle configuration! 4 | compilers: { 5 | solc: { 6 | version: "0.4.17" 7 | } 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/truffle-contract/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | networks: { 4 | development: { 5 | host: "localhost", 6 | port: 8545, 7 | network_id: "*" // Match any network id 8 | } 9 | } 10 | }; 11 | --------------------------------------------------------------------------------