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