mirror of https://gitlab.com/ecentrics/concordia
Ezerous
4 years ago
21 changed files with 4291 additions and 607 deletions
@ -0,0 +1,3 @@ |
|||||
|
body { |
||||
|
margin: 1em !important; |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
import React, { Component } from 'react'; |
||||
|
import PropTypes from 'prop-types'; |
||||
|
|
||||
|
import MenuComponent from './MenuComponent'; |
||||
|
|
||||
|
export default class CoreLayout extends Component { |
||||
|
render() { |
||||
|
return ( |
||||
|
<div> |
||||
|
<MenuComponent/> |
||||
|
{this.props.children} |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
CoreLayout.propTypes = { |
||||
|
children: PropTypes.element.isRequired |
||||
|
}; |
@ -0,0 +1,9 @@ |
|||||
|
import React, { Component } from 'react'; |
||||
|
|
||||
|
class HomeContainer extends Component { |
||||
|
render() { |
||||
|
return(<p>TODO: Home Container</p>); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default HomeContainer; |
@ -0,0 +1,38 @@ |
|||||
|
import React, { Component } from 'react'; |
||||
|
import { withRouter } from "react-router"; |
||||
|
import { Menu } from 'semantic-ui-react'; |
||||
|
|
||||
|
import AppContext from "./AppContext"; |
||||
|
|
||||
|
import app_logo from '../assets/images/app_logo.png'; |
||||
|
import SignUpForm from './SignUpForm'; |
||||
|
|
||||
|
class MenuComponent extends Component { |
||||
|
render() { |
||||
|
return ( |
||||
|
<AppContext.Consumer> |
||||
|
{context => { |
||||
|
return( |
||||
|
<div> |
||||
|
<Menu color='black' inverted> |
||||
|
<Menu.Item |
||||
|
link |
||||
|
name='home' |
||||
|
onClick={() => { this.props.history.push("/"); }} |
||||
|
> |
||||
|
<img src={app_logo} alt="app_logo"/> |
||||
|
</Menu.Item> |
||||
|
|
||||
|
<SignUpForm/> |
||||
|
|
||||
|
</Menu> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
</AppContext.Consumer> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default withRouter(MenuComponent); |
@ -0,0 +1,139 @@ |
|||||
|
import React, { Component } from 'react'; |
||||
|
import { Button, Form, Menu, Message, Modal } from 'semantic-ui-react'; |
||||
|
|
||||
|
import AppContext from "./AppContext"; |
||||
|
import { connect } from 'react-redux'; |
||||
|
|
||||
|
const contractName = 'Forum'; |
||||
|
const checkUsernameTakenMethod = 'isUserNameTaken'; |
||||
|
const signUpMethod = 'signUp'; |
||||
|
|
||||
|
class SignUpForm extends Component { |
||||
|
constructor(props, context) { |
||||
|
super(props, context); |
||||
|
|
||||
|
// For quick access |
||||
|
this.contract = this.context.drizzle.contracts[contractName]; |
||||
|
|
||||
|
this.handleInputChange = this.handleInputChange.bind(this); |
||||
|
this.handleSubmit = this.handleSubmit.bind(this); |
||||
|
this.completeAction = this.completeAction.bind(this); |
||||
|
|
||||
|
this.checkedUsernames = []; |
||||
|
|
||||
|
this.state = { |
||||
|
usernameInput: '', |
||||
|
error: false, |
||||
|
errorHeader: '', |
||||
|
errorMessage: '', |
||||
|
signingUp: false, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
handleInputChange(e, { name, value }) { |
||||
|
this.setState({ |
||||
|
[name]: value, |
||||
|
error: false, |
||||
|
}); |
||||
|
if (value !== '') { |
||||
|
if (this.checkedUsernames.length > 0) { |
||||
|
if (this.checkedUsernames.some((e) => e.usernameChecked === value)) { |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.contract.methods[checkUsernameTakenMethod].cacheCall( |
||||
|
value, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleSubmit() { |
||||
|
const { usernameInput, error } = this.state; |
||||
|
|
||||
|
if (usernameInput === '') { |
||||
|
this.setState({ |
||||
|
error: true, |
||||
|
errorHeader: 'Data Incomplete', |
||||
|
errorMessage: 'You need to provide a username', |
||||
|
}); |
||||
|
} else if (!error) { |
||||
|
// TODO |
||||
|
// // Makes sure current input username has been checked for availability |
||||
|
// if (this.checkedUsernames.some((e) => e.usernameChecked === usernameInput)) { |
||||
|
// this.completeAction(); |
||||
|
// } |
||||
|
this.completeAction(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
componentDidUpdate() { |
||||
|
// TODO |
||||
|
} |
||||
|
|
||||
|
completeAction() { |
||||
|
const { usernameInput } = this.state; |
||||
|
const { user, account } = this.props; |
||||
|
|
||||
|
if (user.hasSignedUp) { |
||||
|
console.log('Signing up..') |
||||
|
this.contract.methods['signUp'].cacheSend(usernameInput); |
||||
|
} else { |
||||
|
this.setState({ |
||||
|
signingUp: true, |
||||
|
}); |
||||
|
this.contract.methods[signUpMethod].cacheSend( |
||||
|
...[usernameInput], { from: account }, |
||||
|
); |
||||
|
} |
||||
|
this.setState({ |
||||
|
usernameInput: '', |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
render() { |
||||
|
const { |
||||
|
error, usernameInput, errorHeader, errorMessage, signingUp, |
||||
|
} = this.state; |
||||
|
|
||||
|
return( |
||||
|
<Modal as={Form} onSubmit={e => this.handleSubmit(e)} trigger={ |
||||
|
<Menu.Item |
||||
|
name='signup' |
||||
|
position='right' |
||||
|
content='Sign Up' |
||||
|
/> |
||||
|
}> |
||||
|
<Modal.Header>Sign Up</Modal.Header> |
||||
|
<Modal.Content> |
||||
|
|
||||
|
<Form.Field required> |
||||
|
<label>Username</label> |
||||
|
<Form.Input |
||||
|
placeholder='Username' |
||||
|
name="usernameInput" |
||||
|
value={usernameInput} |
||||
|
onChange={this.handleInputChange} |
||||
|
/> |
||||
|
</Form.Field> |
||||
|
<Message |
||||
|
error |
||||
|
header={errorHeader} |
||||
|
content={errorMessage} |
||||
|
/> |
||||
|
<Button type="submit" color="black" content="Sign Up" /> |
||||
|
|
||||
|
</Modal.Content> |
||||
|
</Modal> |
||||
|
) |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
SignUpForm.contextType = AppContext.Context; |
||||
|
|
||||
|
const mapStateToProps = (state) => ({ |
||||
|
user: state.user |
||||
|
}); |
||||
|
|
||||
|
export default connect(mapStateToProps)(SignUpForm); |
@ -0,0 +1,2 @@ |
|||||
|
export const USER_DATA_UPDATED = 'USER_DATA_UPDATED'; |
||||
|
export const USER_DATA_ERROR = 'USER_DATA_ERROR'; |
@ -0,0 +1,31 @@ |
|||||
|
import { USER_DATA_UPDATED } from '../actions/userActions'; |
||||
|
|
||||
|
const initialState = { |
||||
|
username: '', |
||||
|
address: null, |
||||
|
hasSignedUp: false, |
||||
|
}; |
||||
|
|
||||
|
const userReducer = (state = initialState, action) => { |
||||
|
const { type } = action; |
||||
|
|
||||
|
if(type === USER_DATA_UPDATED) { |
||||
|
const { address, username } = action; |
||||
|
if(username){ |
||||
|
return { |
||||
|
username: username, |
||||
|
address: address, |
||||
|
hasSignedUp: true, |
||||
|
}; |
||||
|
} |
||||
|
return { |
||||
|
username: '', |
||||
|
address, |
||||
|
hasSignedUp: false, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
return state; |
||||
|
}; |
||||
|
|
||||
|
export default userReducer; |
@ -0,0 +1,42 @@ |
|||||
|
import { all, call, put, take } from 'redux-saga/effects'; |
||||
|
|
||||
|
import { drizzleActions } from '@ezerous/drizzle'; |
||||
|
import { USER_DATA_UPDATED, USER_DATA_ERROR } from '../actions/userActions'; |
||||
|
|
||||
|
function * fetchUserData ({drizzle, account}) { |
||||
|
const contract = drizzle.contracts['Forum']; |
||||
|
const transaction = yield call(contract.methods.hasUserSignedUp, account); |
||||
|
|
||||
|
try { |
||||
|
const dispatchArgs = { address: account }; |
||||
|
const callResult = yield call(transaction.call, { address: account }); |
||||
|
|
||||
|
// User has signed up, fetch his username
|
||||
|
if (callResult) { |
||||
|
const txObj2 = yield call(contract.methods.getUsername, account); |
||||
|
dispatchArgs.username = yield call(txObj2.call, { |
||||
|
address: account |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
yield put({ |
||||
|
type: USER_DATA_UPDATED, ...dispatchArgs |
||||
|
}); |
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error(error); |
||||
|
yield put({ type: USER_DATA_ERROR }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function * userSaga () { |
||||
|
const res = yield all([ |
||||
|
take(drizzleActions.drizzle.DRIZZLE_INITIALIZED), |
||||
|
take(drizzleActions.account.ACCOUNTS_FETCHED) |
||||
|
]); |
||||
|
|
||||
|
yield fetchUserData({drizzle:res[0].drizzle, account: res[1].accounts[0]}); |
||||
|
} |
||||
|
|
||||
|
export default userSaga |
@ -0,0 +1,12 @@ |
|||||
|
{ |
||||
|
"name": "concordia-rendezvous", |
||||
|
"version": "0.1.0", |
||||
|
"private": true, |
||||
|
"description": "Rendezvous server for Concordia", |
||||
|
"scripts": { |
||||
|
"rendezvous": "star-signal --port=9090 --host=127.0.0.1" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"libp2p-webrtc-star": "~0.20.1" |
||||
|
} |
||||
|
} |
File diff suppressed because it is too large
Loading…
Reference in new issue