mirror of https://gitlab.com/ecentrics/concordia
Ezerous
7 years ago
35 changed files with 346 additions and 787 deletions
@ -1,15 +0,0 @@ |
|||
{ |
|||
"short_name": "Apella", |
|||
"name": "Apella", |
|||
"icons": [ |
|||
{ |
|||
"src": "favicon.ico", |
|||
"sizes": "64x64 32x32 24x24 16x16", |
|||
"type": "image/x-icon" |
|||
} |
|||
], |
|||
"start_url": "./index.html", |
|||
"display": "standalone", |
|||
"theme_color": "#000000", |
|||
"background_color": "#ffffff" |
|||
} |
@ -1,52 +1,19 @@ |
|||
import React, { Component } from 'react' |
|||
import { Link } from 'react-router' |
|||
import { HiddenOnlyAuth, VisibleOnlyAuth } from './util/wrappers.js' |
|||
|
|||
// UI Components
|
|||
import LoginButtonContainer from './user/ui/loginbutton/LoginButtonContainer' |
|||
|
|||
// Styles
|
|||
import './css/oswald.css' |
|||
import './css/open-sans.css' |
|||
import './css/pure-min.css' |
|||
import './App.css' |
|||
import './css/App.css' |
|||
|
|||
class App extends Component { |
|||
render() { |
|||
const OnlyAuthLinks = VisibleOnlyAuth(() => |
|||
<span> |
|||
<li className="pure-menu-item"> |
|||
<Link to="/dashboard" className="pure-menu-link">Dashboard</Link> |
|||
</li> |
|||
<li className="pure-menu-item"> |
|||
<Link to="/profile" className="pure-menu-link">Profile</Link> |
|||
</li> |
|||
</span> |
|||
); |
|||
|
|||
const OnlyGuestLinks = HiddenOnlyAuth(() => |
|||
<span> |
|||
<li className="pure-menu-item"> |
|||
<Link to="/signup" className="pure-menu-link">Sign Up</Link> |
|||
</li> |
|||
<LoginButtonContainer /> |
|||
</span> |
|||
); |
|||
|
|||
return ( |
|||
<div className="App"> |
|||
<nav className="navbar pure-menu pure-menu-horizontal"> |
|||
<ul className="pure-menu-list navbar-right"> |
|||
<OnlyGuestLinks /> |
|||
<OnlyAuthLinks /> |
|||
</ul> |
|||
<Link to="/" className="pure-menu-heading pure-menu-link">Apella</Link> |
|||
</nav> |
|||
|
|||
{this.props.children} |
|||
</div> |
|||
); |
|||
} |
|||
render() { |
|||
return ( |
|||
<div className="App"> |
|||
{this.props.children} |
|||
</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
export default App |
|||
|
@ -0,0 +1,48 @@ |
|||
import { drizzleConnect } from 'drizzle-react' |
|||
import React, { Component } from 'react' |
|||
import PropTypes from 'prop-types' |
|||
|
|||
const contract = "Forum"; |
|||
const method = "hasUserSignedUp"; |
|||
|
|||
class AuthWrapperContainer extends Component { |
|||
constructor(props, context) { |
|||
super(props); |
|||
|
|||
this.contracts = context.drizzle.contracts; |
|||
|
|||
this.dataKey = this.contracts[contract].methods[method].cacheCall(...[this.props.accounts[0]]); |
|||
} |
|||
|
|||
render() { |
|||
// Contract is not yet intialized.
|
|||
if(!this.props.contracts[contract].initialized) |
|||
return (null); |
|||
|
|||
// If the cache key we received earlier isn't in the store yet; the initial value is still being fetched.
|
|||
if(!(this.dataKey in this.props.contracts[contract][method])) |
|||
return (null); |
|||
|
|||
let userHasSignedUp = this.props.contracts[contract][method][this.dataKey].value; |
|||
const authRender = this.props.authRender; |
|||
const guestRender = this.props.guestRender; |
|||
|
|||
if (userHasSignedUp) |
|||
return(<div>{authRender}</div>); |
|||
|
|||
return(<div>{guestRender}</div>); |
|||
} |
|||
} |
|||
|
|||
AuthWrapperContainer.contextTypes = { |
|||
drizzle: PropTypes.object |
|||
}; |
|||
|
|||
const mapStateToProps = state => { |
|||
return { |
|||
accounts: state.accounts, |
|||
contracts: state.contracts, |
|||
} |
|||
}; |
|||
|
|||
export default drizzleConnect(AuthWrapperContainer, mapStateToProps) |
@ -0,0 +1,103 @@ |
|||
import { drizzleConnect } from 'drizzle-react' |
|||
import React, { Component } from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import AuthWrapperContainer from './AuthWrapperContainer' |
|||
|
|||
const contract = "Forum"; |
|||
const signUpMethod = "signUp"; |
|||
const updateUsernameMethod ="updateUsername"; |
|||
|
|||
class UsernameFormContainer extends Component { |
|||
constructor(props, context) { |
|||
super(props); |
|||
|
|||
this.handleSignUp = this.handleSignUp.bind(this); |
|||
this.handleSignUpInputChange = this.handleSignUpInputChange.bind(this); |
|||
|
|||
this.handleUsernameUpdate = this.handleUsernameUpdate.bind(this); |
|||
this.handleUpdateUsernameInputChange = this.handleUpdateUsernameInputChange.bind(this); |
|||
|
|||
this.contracts = context.drizzle.contracts; |
|||
|
|||
// Get the contract ABI
|
|||
const abi = this.contracts[contract].abi; |
|||
|
|||
|
|||
this.inputs = {signUp:[], updateUsername:[]}; |
|||
let initialState = {signUp:{}, updateUsername:{}}; |
|||
|
|||
// Iterate over abi for correct function.
|
|||
for (let i = 0; i < abi.length; i++) { |
|||
if ((abi[i].name === signUpMethod)) { |
|||
this.inputs.signUp = abi[i].inputs; |
|||
|
|||
for (let i = 0; i < this.inputs.signUp.length; i++) { |
|||
initialState.signUp[this.inputs.signUp[i].name] = ''; |
|||
} |
|||
|
|||
} |
|||
else if ((abi[i].name === updateUsernameMethod)) { |
|||
this.inputs.updateUsername = abi[i].inputs; |
|||
|
|||
for (let i = 0; i < this.inputs.updateUsername.length; i++) { |
|||
initialState.updateUsername[this.inputs.updateUsername[i].name] = ''; |
|||
} |
|||
|
|||
} |
|||
} |
|||
console.dir(initialState); |
|||
this.state = initialState; |
|||
} |
|||
|
|||
handleSignUp() { |
|||
this.contracts[contract].methods[signUpMethod].cacheSend(...Object.values(this.state.signUp)); |
|||
} |
|||
|
|||
handleUsernameUpdate() { |
|||
this.contracts[contract].methods[updateUsernameMethod].cacheSend(...Object.values(this.state.updateUsername)); |
|||
} |
|||
|
|||
handleSignUpInputChange(event) { |
|||
this.setState({ signUp: { ...this.state.signUp, [event.target.name]: event.target.value} }); |
|||
} |
|||
|
|||
handleUpdateUsernameInputChange(event) { |
|||
this.setState({ updateUsername: { ...this.state.updateUsername, [event.target.name]: event.target.value} }); |
|||
} |
|||
|
|||
|
|||
render() { |
|||
let signUp = this.inputs.signUp[0].name; //username
|
|||
let updateUsername = this.inputs.updateUsername[0].name; //newUsername
|
|||
return ( |
|||
<AuthWrapperContainer |
|||
authRender={ |
|||
<form className="pure-form pure-form-stacked"> |
|||
<input key={updateUsername} name={updateUsername} type="text" value={this.state.updateUsername.newUsername} placeholder="Username" onChange={this.handleUpdateUsernameInputChange} /> |
|||
<button key="submit" className="pure-button" type="button" onClick={this.handleUsernameUpdate}>Update</button> |
|||
</form> |
|||
} |
|||
guestRender={ |
|||
<form className="pure-form pure-form-stacked"> |
|||
<input key={signUp} name={signUp} type="text" value={this.state.signUp.username} placeholder="Username" onChange={this.handleSignUpInputChange} /> |
|||
<button key="submit" className="pure-button" type="button" onClick={this.handleSignUp}>Sign Up</button> |
|||
</form> |
|||
} |
|||
/> |
|||
|
|||
|
|||
) |
|||
} |
|||
} |
|||
|
|||
UsernameFormContainer.contextTypes = { |
|||
drizzle: PropTypes.object |
|||
}; |
|||
|
|||
const mapStateToProps = state => { |
|||
return { |
|||
contracts: state.contracts |
|||
} |
|||
}; |
|||
|
|||
export default drizzleConnect(UsernameFormContainer, mapStateToProps) |
@ -0,0 +1,18 @@ |
|||
import Forum from './build/contracts/Forum.json' |
|||
|
|||
const drizzleOptions = { |
|||
web3: { |
|||
fallback: { |
|||
type: 'ws', |
|||
url: 'ws://127.0.0.1:8545' |
|||
} |
|||
}, |
|||
contracts: [ |
|||
Forum |
|||
], |
|||
events: { |
|||
Forum: ['UserSignedUp'] |
|||
} |
|||
}; |
|||
|
|||
export default drizzleOptions |
@ -1,23 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
|
|||
class Dashboard extends Component { |
|||
constructor(props, { authData }) { |
|||
super(props); |
|||
authData = this.props |
|||
} |
|||
|
|||
render() { |
|||
return( |
|||
<main className="container"> |
|||
<div className="pure-g"> |
|||
<div className="pure-u-1-1"> |
|||
<h1>Dashboard</h1> |
|||
<p><strong>Congratulations {this.props.authData.name}!</strong> If you're seeing this page, you've logged in with your own smart contract successfully.</p> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default Dashboard |
@ -0,0 +1,15 @@ |
|||
import Home from './Home' |
|||
import { drizzleConnect } from 'drizzle-react' |
|||
|
|||
// May still need this even with data function to refresh component on updates for this contract.
|
|||
const mapStateToProps = state => { |
|||
return { |
|||
accounts: state.accounts, |
|||
Forum: state.contracts.Forum, |
|||
drizzleStatus: state.drizzleStatus |
|||
} |
|||
}; |
|||
|
|||
const HomeContainer = drizzleConnect(Home, mapStateToProps); |
|||
|
|||
export default HomeContainer |
@ -1,12 +1,10 @@ |
|||
import { combineReducers } from 'redux' |
|||
import { routerReducer } from 'react-router-redux' |
|||
import userReducer from './user/userReducer' |
|||
import web3Reducer from './util/web3/web3Reducer' |
|||
import { drizzleReducers } from 'drizzle' |
|||
|
|||
const reducer = combineReducers({ |
|||
routing: routerReducer, |
|||
user: userReducer, |
|||
web3: web3Reducer |
|||
...drizzleReducers |
|||
}); |
|||
|
|||
export default reducer |
|||
|
@ -1,117 +0,0 @@ |
|||
// In production, we register a service worker to serve assets from local cache.
|
|||
|
|||
// This lets the app load faster on subsequent visits in production, and gives
|
|||
// it offline capabilities. However, it also means that developers (and users)
|
|||
// will only see deployed updates on the "N+1" visit to a page, since previously
|
|||
// cached resources are updated in the background.
|
|||
|
|||
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
|
|||
// This link also includes instructions on opting out of this behavior.
|
|||
|
|||
const isLocalhost = Boolean( |
|||
window.location.hostname === 'localhost' || |
|||
// [::1] is the IPv6 localhost address.
|
|||
window.location.hostname === '[::1]' || |
|||
// 127.0.0.1/8 is considered localhost for IPv4.
|
|||
window.location.hostname.match( |
|||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ |
|||
) |
|||
); |
|||
|
|||
export default function register() { |
|||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { |
|||
// The URL constructor is available in all browsers that support SW.
|
|||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location); |
|||
if (publicUrl.origin !== window.location.origin) { |
|||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
|||
// from what our page is served on. This might happen if a CDN is used to
|
|||
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
|
|||
return; |
|||
} |
|||
|
|||
window.addEventListener('load', () => { |
|||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; |
|||
|
|||
if (isLocalhost) { |
|||
// This is running on localhost. Lets check if a service worker still exists or not.
|
|||
checkValidServiceWorker(swUrl); |
|||
|
|||
// Add some additional logging to localhost, pointing developers to the
|
|||
// service worker/PWA documentation.
|
|||
navigator.serviceWorker.ready.then(() => { |
|||
console.log( |
|||
'This web app is being served cache-first by a service ' + |
|||
'worker. To learn more, visit https://goo.gl/SC7cgQ' |
|||
); |
|||
}); |
|||
} else { |
|||
// Is not local host. Just register service worker
|
|||
registerValidSW(swUrl); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function registerValidSW(swUrl) { |
|||
navigator.serviceWorker |
|||
.register(swUrl) |
|||
.then(registration => { |
|||
registration.onupdatefound = () => { |
|||
const installingWorker = registration.installing; |
|||
installingWorker.onstatechange = () => { |
|||
if (installingWorker.state === 'installed') { |
|||
if (navigator.serviceWorker.controller) { |
|||
// At this point, the old content will have been purged and
|
|||
// the fresh content will have been added to the cache.
|
|||
// It's the perfect time to display a "New content is
|
|||
// available; please refresh." message in your web app.
|
|||
console.log('New content is available; please refresh.'); |
|||
} else { |
|||
// At this point, everything has been precached.
|
|||
// It's the perfect time to display a
|
|||
// "Content is cached for offline use." message.
|
|||
console.log('Content is cached for offline use.'); |
|||
} |
|||
} |
|||
}; |
|||
}; |
|||
}) |
|||
.catch(error => { |
|||
console.error('Error during service worker registration:', error); |
|||
}); |
|||
} |
|||
|
|||
function checkValidServiceWorker(swUrl) { |
|||
// Check if the service worker can be found. If it can't reload the page.
|
|||
fetch(swUrl) |
|||
.then(response => { |
|||
// Ensure service worker exists, and that we really are getting a JS file.
|
|||
if ( |
|||
response.status === 404 || |
|||
response.headers.get('content-type').indexOf('javascript') === -1 |
|||
) { |
|||
// No service worker found. Probably a different app. Reload the page.
|
|||
navigator.serviceWorker.ready.then(registration => { |
|||
registration.unregister().then(() => { |
|||
window.location.reload(); |
|||
}); |
|||
}); |
|||
} else { |
|||
// Service worker found. Proceed as normal.
|
|||
registerValidSW(swUrl); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
console.log( |
|||
'No internet connection found. App is running in offline mode.' |
|||
); |
|||
}); |
|||
} |
|||
|
|||
export function unregister() { |
|||
if ('serviceWorker' in navigator) { |
|||
navigator.serviceWorker.ready.then(registration => { |
|||
registration.unregister(); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
import { all, fork } from 'redux-saga/effects' |
|||
import { drizzleSagas } from 'drizzle' |
|||
|
|||
export default function* root() { |
|||
yield all( |
|||
drizzleSagas.map(saga => fork(saga)) |
|||
) |
|||
} |
@ -1,22 +1,33 @@ |
|||
import { browserHistory } from 'react-router' |
|||
import { createStore, applyMiddleware, compose } from 'redux' |
|||
import thunkMiddleware from 'redux-thunk' |
|||
import { routerMiddleware } from 'react-router-redux' |
|||
import reducer from './reducer' |
|||
import rootSaga from './rootSaga' |
|||
import createSagaMiddleware from 'redux-saga' |
|||
import { generateContractsInitialState } from 'drizzle' |
|||
import drizzleOptions from './drizzleOptions' |
|||
|
|||
// Redux DevTools (see also https://github.com/zalmoxisus/redux-devtools-extension#12-advanced-store-setup)
|
|||
// Redux DevTools
|
|||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; |
|||
|
|||
const routingMiddleware = routerMiddleware(browserHistory); |
|||
const sagaMiddleware = createSagaMiddleware(); |
|||
|
|||
const initialState = { |
|||
contracts: generateContractsInitialState(drizzleOptions) |
|||
}; |
|||
|
|||
const store = createStore( |
|||
reducer, |
|||
initialState, |
|||
composeEnhancers( |
|||
applyMiddleware( |
|||
thunkMiddleware, |
|||
routingMiddleware |
|||
routingMiddleware, |
|||
sagaMiddleware |
|||
) |
|||
) |
|||
); |
|||
|
|||
sagaMiddleware.run(rootSaga); |
|||
|
|||
export default store |
@ -1,20 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
import ProfileFormContainer from '../../ui/profileform/ProfileFormContainer' |
|||
|
|||
class Profile extends Component { |
|||
render() { |
|||
return( |
|||
<main className="container"> |
|||
<div className="pure-g"> |
|||
<div className="pure-u-1-1"> |
|||
<h1>Profile</h1> |
|||
<p>Edit your account details here.</p> |
|||
<ProfileFormContainer /> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default Profile |
@ -1,20 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
import SignUpFormContainer from '../../ui/signupform/SignUpFormContainer' |
|||
|
|||
class SignUp extends Component { |
|||
render() { |
|||
return( |
|||
<main className="container"> |
|||
<div className="pure-g"> |
|||
<div className="pure-u-1-1"> |
|||
<h1>Sign Up</h1> |
|||
<p>We've got your wallet information, simply input your name and your account is made!</p> |
|||
<SignUpFormContainer /> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default SignUp |
@ -1,11 +0,0 @@ |
|||
import React from 'react' |
|||
|
|||
const LoginButton = ({ onLoginUserClick }) => { |
|||
return( |
|||
<li className="pure-menu-item"> |
|||
<a href="" className="pure-menu-link" onClick={(event) => onLoginUserClick(event)}>Login</a> |
|||
</li> |
|||
) |
|||
}; |
|||
|
|||
export default LoginButton |
@ -1,69 +0,0 @@ |
|||
import ForumContract from '../../../build/contracts/Forum.json' |
|||
import { browserHistory } from 'react-router' |
|||
import store from '../../../store' |
|||
|
|||
const contract = require('truffle-contract'); |
|||
|
|||
export const USER_LOGGED_IN = 'USER_LOGGED_IN'; |
|||
function userLoggedIn(user) { |
|||
return { |
|||
type: USER_LOGGED_IN, |
|||
payload: user |
|||
} |
|||
} |
|||
|
|||
export function loginUser() { |
|||
let web3 = store.getState().web3.web3Instance; |
|||
|
|||
// Double-check web3's status.
|
|||
if (typeof web3 !== 'undefined') { |
|||
|
|||
return function(dispatch) { |
|||
// Using truffle-contract we create the authentication object.
|
|||
const authentication = contract(ForumContract); |
|||
authentication.setProvider(web3.currentProvider); |
|||
|
|||
// Declaring this for later so we can chain functions on Authentication.
|
|||
let authenticationInstance; |
|||
|
|||
// Get current ethereum wallet.
|
|||
web3.eth.getCoinbase((error, coinbase) => { |
|||
// Log errors, if any.
|
|||
if (error) { |
|||
console.error(error); |
|||
} |
|||
|
|||
authentication.deployed().then(function(instance) { |
|||
authenticationInstance = instance; |
|||
|
|||
// Attempt to login user.
|
|||
authenticationInstance.login({from: coinbase}) |
|||
.then(function(result) { |
|||
// If no error, login user.
|
|||
console.log("Login successful: " + JSON.parse(result)); |
|||
dispatch(userLoggedIn({"name": JSON.parse(result)})); |
|||
|
|||
// Used a manual redirect here as opposed to a wrapper.
|
|||
// This way, once logged in a user can still access the home page.
|
|||
let currentLocation = browserHistory.getCurrentLocation(); |
|||
|
|||
if ('redirect' in currentLocation.query) |
|||
return browserHistory.push(decodeURIComponent(currentLocation.query.redirect)); |
|||
|
|||
|
|||
return browserHistory.push('/dashboard') |
|||
}) |
|||
.catch(function(result) { |
|||
// If error, go to signup page.
|
|||
console.error('Wallet ' + coinbase + ' does not have an account!'); |
|||
console.error('Error: ' + result); |
|||
|
|||
return browserHistory.push('/signup') |
|||
}) |
|||
}) |
|||
}) |
|||
} |
|||
} else { |
|||
console.error('Web3 is not initialized.'); |
|||
} |
|||
} |
@ -1,23 +0,0 @@ |
|||
import { connect } from 'react-redux' |
|||
import LoginButton from './LoginButton' |
|||
import { loginUser } from './LoginButtonActions' |
|||
|
|||
const mapStateToProps = (state, ownProps) => { |
|||
return {} |
|||
}; |
|||
|
|||
const mapDispatchToProps = (dispatch) => { |
|||
return { |
|||
onLoginUserClick: (event) => { |
|||
event.preventDefault(); |
|||
dispatch(loginUser()); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const LoginButtonContainer = connect( |
|||
mapStateToProps, |
|||
mapDispatchToProps |
|||
)(LoginButton); |
|||
|
|||
export default LoginButtonContainer |
@ -1,42 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
|
|||
class ProfileForm extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
|
|||
this.state = { |
|||
name: this.props.name |
|||
} |
|||
} |
|||
|
|||
onInputChange(event) { |
|||
this.setState({ name: event.target.value }) |
|||
} |
|||
|
|||
handleSubmit(event) { |
|||
event.preventDefault(); |
|||
|
|||
if (this.state.name.length < 2) |
|||
return alert('Please fill in your name.'); |
|||
|
|||
this.props.onProfileFormSubmit(this.state.name, event) |
|||
} |
|||
|
|||
render() { |
|||
return( |
|||
<form className="pure-form pure-form-stacked" onSubmit={this.handleSubmit.bind(this)}> |
|||
<fieldset> |
|||
<label htmlFor="name">Name</label> |
|||
<input id="name" type="text" value={this.state.name} onChange={this.onInputChange.bind(this)} placeholder="Name" /> |
|||
<span className="pure-form-message">This is a required field.</span> |
|||
|
|||
<br /> |
|||
|
|||
<button type="submit" className="pure-button pure-button-primary">Update</button> |
|||
</fieldset> |
|||
</form> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default ProfileForm |
@ -1,56 +0,0 @@ |
|||
import ForumContract from '../../../build/contracts/Forum.json' |
|||
import store from '../../../store' |
|||
|
|||
const contract = require('truffle-contract'); |
|||
|
|||
export const USER_UPDATED = 'USER_UPDATED'; |
|||
function userUpdated(user) { |
|||
return { |
|||
type: USER_UPDATED, |
|||
payload: user |
|||
} |
|||
} |
|||
|
|||
export function updateUser(name) { |
|||
let web3 = store.getState().web3.web3Instance; |
|||
|
|||
// Double-check web3's status.
|
|||
if (typeof web3 !== 'undefined') { |
|||
|
|||
return function(dispatch) { |
|||
// Using truffle-contract we create the authentication object.
|
|||
const authentication = contract(ForumContract); |
|||
authentication.setProvider(web3.currentProvider); |
|||
|
|||
// Declaring this for later so we can chain functions on Authentication.
|
|||
let authenticationInstance; |
|||
|
|||
// Get current ethereum wallet.
|
|||
web3.eth.getCoinbase((error, coinbase) => { |
|||
// Log errors, if any.
|
|||
if (error) { |
|||
console.error(error); |
|||
} |
|||
|
|||
authentication.deployed().then(function(instance) { |
|||
authenticationInstance = instance; |
|||
|
|||
// Attempt to login user.
|
|||
authenticationInstance.signUp(JSON.stringify(name), {from: coinbase}) |
|||
.then(function(result) { |
|||
console.log("SignUp/name update successful: " + name); |
|||
// If no error, update user.
|
|||
dispatch(userUpdated({"name": name})); |
|||
|
|||
return alert('Name updated!') |
|||
}) |
|||
.catch(function(result) { |
|||
// If error...
|
|||
}) |
|||
}) |
|||
}) |
|||
} |
|||
} else { |
|||
console.error('Web3 is not initialized.'); |
|||
} |
|||
} |
@ -1,25 +0,0 @@ |
|||
import { connect } from 'react-redux' |
|||
import ProfileForm from './ProfileForm' |
|||
import { updateUser } from './ProfileFormActions' |
|||
|
|||
const mapStateToProps = (state, ownProps) => { |
|||
return { |
|||
name: state.user.data.name |
|||
} |
|||
}; |
|||
|
|||
const mapDispatchToProps = (dispatch) => { |
|||
return { |
|||
onProfileFormSubmit: (name, event) => { |
|||
event.preventDefault(); |
|||
dispatch(updateUser(name)) |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const ProfileFormContainer = connect( |
|||
mapStateToProps, |
|||
mapDispatchToProps |
|||
)(ProfileForm); |
|||
|
|||
export default ProfileFormContainer |
@ -1,44 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
|
|||
class SignUpForm extends Component { |
|||
constructor(props) { |
|||
super(props); |
|||
|
|||
this.state = { |
|||
name: '' |
|||
} |
|||
} |
|||
|
|||
onInputChange(event) { |
|||
this.setState({ name: event.target.value }) |
|||
} |
|||
|
|||
handleSubmit(event) { |
|||
event.preventDefault(); |
|||
|
|||
if (this.state.name.length < 2) |
|||
{ |
|||
return alert('Please fill in your name.') |
|||
} |
|||
|
|||
this.props.onSignUpFormSubmit(this.state.name) |
|||
} |
|||
|
|||
render() { |
|||
return( |
|||
<form className="pure-form pure-form-stacked" onSubmit={this.handleSubmit.bind(this)}> |
|||
<fieldset> |
|||
<label htmlFor="name">Name</label> |
|||
<input id="name" type="text" value={this.state.name} onChange={this.onInputChange.bind(this)} placeholder="Name" /> |
|||
<span className="pure-form-message">This is a required field.</span> |
|||
|
|||
<br /> |
|||
|
|||
<button type="submit" className="pure-button pure-button-primary">Sign Up</button> |
|||
</fieldset> |
|||
</form> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default SignUpForm |
@ -1,45 +0,0 @@ |
|||
import ForumContract from '../../../build/contracts/Forum.json' |
|||
import { loginUser } from '../loginbutton/LoginButtonActions' |
|||
import store from '../../../store' |
|||
|
|||
const contract = require('truffle-contract'); |
|||
|
|||
export function signUpUser(name) { |
|||
let web3 = store.getState().web3.web3Instance; |
|||
|
|||
// Double-check web3's status.
|
|||
if (typeof web3 !== 'undefined') { |
|||
|
|||
return function(dispatch) { |
|||
// Using truffle-contract we create the authentication object.
|
|||
const authentication = contract(ForumContract); |
|||
authentication.setProvider(web3.currentProvider); |
|||
|
|||
// Declaring this for later so we can chain functions on Authentication.
|
|||
let authenticationInstance; |
|||
|
|||
// Get current ethereum wallet.
|
|||
web3.eth.getCoinbase((error, coinbase) => { |
|||
// Log errors, if any.
|
|||
if (error) |
|||
console.error(error); |
|||
|
|||
authentication.deployed().then(function(instance) { |
|||
authenticationInstance = instance; |
|||
|
|||
// Attempt to sign up user.
|
|||
authenticationInstance.signUp(JSON.stringify(name), {from: coinbase}) |
|||
.then(function(result) { |
|||
// If no error, login user.
|
|||
return dispatch(loginUser()) |
|||
}) |
|||
.catch(function(result) { |
|||
console.log("SignUp error: " + result); |
|||
}) |
|||
}) |
|||
}) |
|||
} |
|||
} else { |
|||
console.error('Web3 is not initialized.'); |
|||
} |
|||
} |
@ -1,22 +0,0 @@ |
|||
import { connect } from 'react-redux' |
|||
import SignUpForm from './SignUpForm' |
|||
import { signUpUser } from './SignUpFormActions' |
|||
|
|||
const mapStateToProps = (state, ownProps) => { |
|||
return {} |
|||
}; |
|||
|
|||
const mapDispatchToProps = (dispatch) => { |
|||
return { |
|||
onSignUpFormSubmit: (name) => { |
|||
dispatch(signUpUser(name)) |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const SignUpFormContainer = connect( |
|||
mapStateToProps, |
|||
mapDispatchToProps |
|||
)(SignUpForm); |
|||
|
|||
export default SignUpFormContainer |
@ -1,22 +0,0 @@ |
|||
const initialState = { |
|||
data: null |
|||
}; |
|||
|
|||
const userReducer = (state = initialState, action) => { |
|||
if (action.type === 'USER_LOGGED_IN' || action.type === 'USER_UPDATED') |
|||
{ |
|||
return Object.assign({}, state, { |
|||
data: action.payload |
|||
}) |
|||
} |
|||
|
|||
if (action.type === 'USER_LOGGED_OUT') |
|||
{ |
|||
return Object.assign({}, state, { |
|||
data: null |
|||
}) |
|||
} |
|||
return state; |
|||
}; |
|||
|
|||
export default userReducer |
@ -1,51 +0,0 @@ |
|||
import store from '../../store' |
|||
import Web3 from 'web3' |
|||
|
|||
export const WEB3_INITIALIZED = 'WEB3_INITIALIZED'; |
|||
function web3Initialized(results) { |
|||
return { |
|||
type: WEB3_INITIALIZED, |
|||
payload: results |
|||
} |
|||
} |
|||
|
|||
let getWeb3 = new Promise(function(resolve, reject) { |
|||
// Wait for loading completion to avoid race conditions with web3 injection timing.
|
|||
window.addEventListener('load', function(dispatch) { |
|||
var results; |
|||
var web3 = window.web3; |
|||
|
|||
// Checking if Web3 has been injected by the browser (Mist/MetaMask)
|
|||
if (typeof web3 !== 'undefined') { |
|||
// Use Mist/MetaMask's provider.
|
|||
web3 = new Web3(web3.currentProvider); |
|||
|
|||
results = { |
|||
web3Instance: web3 |
|||
}; |
|||
|
|||
console.log('Injected web3 detected.'); |
|||
|
|||
resolve(store.dispatch(web3Initialized(results))) |
|||
} else { |
|||
|
|||
// Fallback to localhost if no web3 injection.
|
|||
|
|||
var provider = new Web3.providers.HttpProvider('http://localhost:8545'); |
|||
|
|||
web3 = new Web3(provider); |
|||
|
|||
results = { |
|||
web3Instance: web3 |
|||
}; |
|||
|
|||
console.log('No web3 instance injected, using Local web3.'); |
|||
|
|||
resolve(store.dispatch(web3Initialized(results))) |
|||
} |
|||
|
|||
// TODO: Error checking.
|
|||
}) |
|||
}); |
|||
|
|||
export default getWeb3 |
@ -1,16 +0,0 @@ |
|||
const initialState = { |
|||
web3Instance: null |
|||
}; |
|||
|
|||
const web3Reducer = (state = initialState, action) => { |
|||
if (action.type === 'WEB3_INITIALIZED') |
|||
{ |
|||
return Object.assign({}, state, { |
|||
web3Instance: action.payload.web3Instance |
|||
}) |
|||
} |
|||
|
|||
return state |
|||
}; |
|||
|
|||
export default web3Reducer |
@ -1,34 +0,0 @@ |
|||
import { UserAuthWrapper } from 'redux-auth-wrapper' |
|||
import { routerActions } from 'react-router-redux' |
|||
|
|||
// Layout Component Wrappers
|
|||
export const UserIsAuthenticated = UserAuthWrapper({ |
|||
authSelector: state => state.user.data, |
|||
redirectAction: routerActions.replace, |
|||
failureRedirectPath: '/', // '/login' by default.
|
|||
wrapperDisplayName: 'UserIsAuthenticated' |
|||
}); |
|||
|
|||
export const UserIsNotAuthenticated = UserAuthWrapper({ |
|||
authSelector: state => state.user, |
|||
redirectAction: routerActions.replace, |
|||
failureRedirectPath: (state, ownProps) => ownProps.location.query.redirect || '/dashboard', |
|||
wrapperDisplayName: 'UserIsNotAuthenticated', |
|||
predicate: user => user.data === null, |
|||
allowRedirectBack: false |
|||
}); |
|||
|
|||
// UI Component Wrappers
|
|||
export const VisibleOnlyAuth = UserAuthWrapper({ |
|||
authSelector: state => state.user, |
|||
wrapperDisplayName: 'VisibleOnlyAuth', |
|||
predicate: user => user.data, |
|||
FailureComponent: null |
|||
}); |
|||
|
|||
export const HiddenOnlyAuth = UserAuthWrapper({ |
|||
authSelector: state => state.user, |
|||
wrapperDisplayName: 'HiddenOnlyAuth', |
|||
predicate: user => user.data === null, |
|||
FailureComponent: null |
|||
}); |
Loading…
Reference in new issue