Browse Source

Fix lint issues

develop
Apostolos Fanakis 4 years ago
parent
commit
40925e2a7a
  1. 2
      packages/concordia-app/package.json
  2. 21
      packages/concordia-app/src/components/App.jsx
  3. 72
      packages/concordia-app/src/components/AppContext.js
  4. 81
      packages/concordia-app/src/components/AppContext.jsx
  5. 20
      packages/concordia-app/src/components/CoreLayoutContainer.jsx
  6. 8
      packages/concordia-app/src/components/HomeContainer.jsx
  7. 78
      packages/concordia-app/src/components/LoadingComponent.jsx
  8. 121
      packages/concordia-app/src/components/LoadingContainer.jsx
  9. 35
      packages/concordia-app/src/components/MenuComponent.jsx
  10. 69
      packages/concordia-app/src/components/SignUpForm.jsx
  11. 13
      packages/concordia-app/src/index.jsx
  12. 22
      packages/concordia-app/src/options/breezeOptions.js
  13. 6
      packages/concordia-app/src/options/drizzleOptions.js
  14. 2
      packages/concordia-app/src/options/web3Options.js
  15. 6
      packages/concordia-app/src/orbit/orbitUtils.js
  16. 72
      packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js
  17. 8
      packages/concordia-app/src/redux/reducers/userReducer.js
  18. 21
      packages/concordia-app/src/redux/sagas/orbitSaga.js
  19. 8
      packages/concordia-app/src/redux/sagas/rootSaga.js
  20. 23
      packages/concordia-app/src/redux/sagas/userSaga.js
  21. 13
      packages/concordia-app/src/redux/store.js
  22. 38
      packages/concordia-app/src/utils/serviceWorker.js

2
packages/concordia-app/package.json

@ -9,7 +9,7 @@
"eject": "react-scripts eject",
"postinstall": "patch-package",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"lint": "yarn run eslint . --format table"
"lint": "yarn run eslint --ext js,jsx . --format table"
},
"browserslist": {
"production": [

21
packages/concordia-app/src/components/App.jsx

@ -1,16 +1,15 @@
import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import LoadingContainer from './LoadingContainer'
import PropTypes from 'prop-types'
import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import PropTypes from 'prop-types';
import LoadingContainer from './LoadingContainer';
// CSS
import '../assets/css/app.css';
import CoreLayoutContainer from './CoreLayoutContainer';
import HomeContainer from './HomeContainer';
import NotFound from '../components/NotFound';
import NotFound from './NotFound';
const App = ({ store }) => (
<Provider store={store}>
@ -25,10 +24,10 @@ const App = ({ store }) => (
</Router>
</LoadingContainer>
</Provider>
)
);
App.propTypes = {
store: PropTypes.object.isRequired
}
store: PropTypes.object.isRequired,
};
export default App
export default App;

72
packages/concordia-app/src/components/AppContext.js

@ -1,72 +0,0 @@
// Modified version of https://github.com/trufflesuite/drizzle/blob/develop/packages/react-plugin/src/DrizzleContext.js
import React from "react";
const Context = React.createContext();
class Provider extends React.Component {
state = {
drizzleState: null,
drizzleInitialized: false,
breezeState: null,
breezeInitialized: false
};
componentDidMount() {
const { drizzle, breeze } = this.props;
// subscribe to changes in the store, keep state up-to-date
this.unsubscribe = drizzle.store.subscribe(() => {
const drizzleState = drizzle.store.getState();
const breezeState = breeze.store.getState();
if (drizzleState.drizzleStatus.initialized) {
this.setState({
drizzleState,
drizzleInitialized: true
});
}
if (breezeState.breezeStatus.initialized) {
this.setState({
breezeState: breezeState,
breezeInitialized: true
});
}
});
this.unsubscribe = breeze.store.subscribe(() => {
const breezeState = breeze.store.getState();
if (breezeState.breezeStatus.initialized) {
this.setState({
breezeState: breezeState,
breezeInitialized: true
});
}
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
return (
<Context.Provider
value={{
drizzle: this.props.drizzle,
drizzleState: this.state.drizzleState,
drizzleInitialized: this.state.drizzleInitialized,
breeze: this.props.breeze,
breezeState: this.state.breezeState,
breezeInitialized: this.state.breezeInitialized
}}
>
{this.props.children}
</Context.Provider>
);
}
}
export default {
Context: Context,
Consumer: Context.Consumer,
Provider
};

81
packages/concordia-app/src/components/AppContext.jsx

@ -0,0 +1,81 @@
// Modified version of https://github.com/trufflesuite/drizzle/blob/develop/packages/react-plugin/src/DrizzleContext.js
import React from 'react';
const Context = React.createContext();
class Provider extends React.Component {
constructor(props) {
super(props);
this.state = {
drizzleState: null,
drizzleInitialized: false,
breezeState: null,
breezeInitialized: false,
};
}
componentDidMount() {
const { drizzle, breeze } = this.props;
// subscribe to changes in the store, keep state up-to-date
this.unsubscribe = drizzle.store.subscribe(() => {
const drizzleState = drizzle.store.getState();
const breezeState = breeze.store.getState();
if (drizzleState.drizzleStatus.initialized) {
this.setState({
drizzleState,
drizzleInitialized: true,
});
}
if (breezeState.breezeStatus.initialized) {
this.setState({
breezeState,
breezeInitialized: true,
});
}
});
this.unsubscribe = breeze.store.subscribe(() => {
const breezeState = breeze.store.getState();
if (breezeState.breezeStatus.initialized) {
this.setState({
breezeState,
breezeInitialized: true,
});
}
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const {
drizzleState, drizzleInitialized, breezeState, breezeInitialized,
} = this.state;
const { drizzle, breeze, children } = this.props;
return (
<Context.Provider
value={{
drizzle,
drizzleState,
drizzleInitialized,
breeze,
breezeState,
breezeInitialized,
}}
>
{children}
</Context.Provider>
);
}
}
export default {
Context,
Consumer: Context.Consumer,
Provider,
};

20
packages/concordia-app/src/components/CoreLayoutContainer.jsx

@ -1,19 +1,21 @@
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import MenuComponent from './MenuComponent';
export default class CoreLayout extends Component {
render() {
const CoreLayout = (props) => {
const { children } = props;
return (
<div>
<MenuComponent/>
{this.props.children}
<MenuComponent />
{children}
</div>
)
}
}
);
};
CoreLayout.propTypes = {
children: PropTypes.element.isRequired
children: PropTypes.element.isRequired,
};
export default CoreLayout;

8
packages/concordia-app/src/components/HomeContainer.jsx

@ -1,9 +1,5 @@
import React, { Component } from 'react';
import React from 'react';
class HomeContainer extends Component {
render() {
return(<p>TODO: Home Container</p>);
}
}
const HomeContainer = () => (<p>TODO: Home Container</p>);
export default HomeContainer;

78
packages/concordia-app/src/components/LoadingComponent.jsx

@ -1,4 +1,4 @@
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { Container, Progress } from 'semantic-ui-react';
@ -7,67 +7,61 @@ import { Container, Progress } from 'semantic-ui-react';
import '../assets/css/loading-component.css';
// Images
import ethereum_logo from '../assets/images/ethereum_logo.svg';
import ipfs_logo from '../assets/images/ipfs_logo.svg';
import orbitdb_logo from '../assets/images/orbitdb_logo.png';
import app_logo from '../assets/images/app_logo.png';
import ethereumLogo from '../assets/images/ethereum_logo.svg';
import ipfsLogo from '../assets/images/ipfs_logo.svg';
import orbitdbLogo from '../assets/images/orbitdb_logo.png';
import appLogo from '../assets/images/app_logo.png';
class LoadingComponent extends Component {
render(){
const { image_type, message_list, progress_type } = this.props ;
let imageSrc, imageAlt, listItems, indicating, error;
const LoadingComponent = (props) => {
const {
imageType, messageList, progressType, title, message, progress,
} = props;
let imageSrc; let imageAlt; let listItems; let indicating; let
error;
if (image_type === "ethereum"){
imageSrc = ethereum_logo;
imageAlt = "ethereum_logo";
}
else if (image_type === "ipfs"){
imageSrc = ipfs_logo;
imageAlt = "ipfs_logo";
}
else if (image_type === "orbit"){
imageSrc = orbitdb_logo;
imageAlt = "orbitdb_logo";
}
else if (image_type === "app"){
imageSrc = app_logo;
imageAlt = "app_logo";
if (imageType === 'ethereum') {
imageSrc = ethereumLogo;
imageAlt = 'ethereum_logo';
} else if (imageType === 'ipfs') {
imageSrc = ipfsLogo;
imageAlt = 'ipfs_logo';
} else if (imageType === 'orbit') {
imageSrc = orbitdbLogo;
imageAlt = 'orbitdb_logo';
} else if (imageType === 'app') {
imageSrc = appLogo;
imageAlt = 'app_logo';
}
if(progress_type === "indicating")
indicating = true;
else if(progress_type === "error")
error = true;
if (progressType === 'indicating') indicating = true;
else if (progressType === 'error') error = true;
if(message_list){
listItems = message_list.map((listItem) =>
<li>{listItem}</li>
);
if (messageList) {
listItems = messageList.map((listItem) => <li>{listItem}</li>);
}
const list = message_list ? <ul>{listItems}</ul> : '';
const list = messageList ? <ul>{listItems}</ul> : '';
return(
return (
<main className="loading-screen">
<Container>
<img src={imageSrc} alt={imageAlt} className="loading-img" />
<p><strong>{this.props.title}</strong></p>
<p>{this.props.message}</p>
<p><strong>{title}</strong></p>
<p>{message}</p>
{list}
</Container>
<Progress percent={this.props.progress} size='small' indicating={indicating} error={error}/>
<Progress percent={progress} size="small" indicating={indicating} error={error} />
</main>
);
}
}
};
LoadingComponent.propTypes = {
title: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
message_list: PropTypes.arrayOf(PropTypes.string),
image_type: PropTypes.string.isRequired,
messageList: PropTypes.arrayOf(PropTypes.string),
imageType: PropTypes.string.isRequired,
progress: PropTypes.number.isRequired,
progress_type: PropTypes.string.isRequired,
progressType: PropTypes.string.isRequired,
};
export default LoadingComponent;

121
packages/concordia-app/src/components/LoadingContainer.jsx

@ -1,7 +1,7 @@
import React, { Children, Component } from 'react';
import { connect } from 'react-redux';
import { breezeConstants } from '@ezerous/breeze'
import { breezeConstants } from '@ezerous/breeze';
import LoadingComponent from './LoadingComponent';
@ -10,114 +10,145 @@ import '../assets/css/loading-component.css';
class LoadingContainer extends Component {
render() {
if ((this.props.web3.status === 'initializing' || !this.props.web3.networkId)
&& !this.props.web3.networkFailed) {
return <LoadingComponent
const {
web3: {
status, networkId, networkFailed, accountsFailed,
},
drizzleStatus: {
initializing,
failed,
},
contractInitialized, contractDeployed, ipfsStatus, orbitStatus, userFetched, children,
} = this.props;
if ((status === 'initializing' || !networkId)
&& !networkFailed) {
return (
<LoadingComponent
title="Connecting to the Ethereum network..."
message="Please make sure to unlock MetaMask and grant the app the right to connect to your account."
image_type="ethereum"
imageType="ethereum"
progress={20}
progress_type="indicating"
progressType="indicating"
/>
);
}
if (this.props.web3.status === 'failed' || this.props.web3.networkFailed) {
return <LoadingComponent
if (status === 'failed' || networkFailed) {
return (
<LoadingComponent
title="No connection to the Ethereum network!"
message="Please make sure that:"
message_list={['MetaMask is unlocked and pointed to the correct, available network',
'The app has been granted the right to connect to your account']}
image_type="ethereum"
imageType="ethereum"
progress={20}
progress_type="error"
progressType="error"
/>
);
}
if (this.props.web3.status === 'initialized' && this.props.web3.accountsFailed) {
return <LoadingComponent
if (status === 'initialized' && accountsFailed) {
return (
<LoadingComponent
title="We can't find any Ethereum accounts!"
message="Please make sure that MetaMask is unlocked."
image_type="ethereum"
imageType="ethereum"
progress={20}
progress_type="error"
progressType="error"
/>
);
}
if (this.props.drizzleStatus.initializing
|| (!this.props.drizzleStatus.failed && !this.props.contractInitialized && this.props.contractDeployed )){
return <LoadingComponent
if (initializing
|| (!failed && !contractInitialized && contractDeployed)) {
return (
<LoadingComponent
title="Initializing contracts..."
message=""
image_type="ethereum"
imageType="ethereum"
progress={40}
progress_type="indicating"
progressType="indicating"
/>
);
}
if (!this.props.contractDeployed) {
return <LoadingComponent
if (!contractDeployed) {
return (
<LoadingComponent
title="No contracts found on the current network!"
message="Please make sure that you are connected to the correct network and the contracts are deployed."
image_type="ethereum"
imageType="ethereum"
progress={40}
progress_type="error"
progressType="error"
/>
);
}
if (this.props.ipfsStatus === breezeConstants.STATUS_INITIALIZING) {
return <LoadingComponent
if (ipfsStatus === breezeConstants.STATUS_INITIALIZING) {
return (
<LoadingComponent
title="Initializing IPFS..."
message=""
image_type="ipfs"
imageType="ipfs"
progress={60}
progress_type="indicating"
progressType="indicating"
/>
);
}
if (this.props.ipfsStatus === breezeConstants.STATUS_FAILED) {
return <LoadingComponent
if (ipfsStatus === breezeConstants.STATUS_FAILED) {
return (
<LoadingComponent
title="IPFS initialization failed!"
message=""
image_type="ipfs"
imageType="ipfs"
progress={60}
progress_type="error"
progressType="error"
/>
);
}
if (this.props.orbitStatus === breezeConstants.STATUS_INITIALIZING) {
if (orbitStatus === breezeConstants.STATUS_INITIALIZING) {
const message = process.env.NODE_ENV === 'development'
? 'If needed, please sign the transaction in MetaMask to create the databases.'
: 'Please sign the transaction in MetaMask to create the databases.';
return <LoadingComponent
return (
<LoadingComponent
title="Preparing OrbitDB..."
message={message}
image_type="orbit"
imageType="orbit"
progress={80}
progress_type="indicating"
progressType="indicating"
/>
);
}
if (this.props.orbitStatus === breezeConstants.STATUS_FAILED) {
return <LoadingComponent
if (orbitStatus === breezeConstants.STATUS_FAILED) {
return (
<LoadingComponent
title="OrbitDB initialization failed!"
message=""
image_type="orbit"
imageType="orbit"
progress={80}
progress_type="error"
progressType="error"
/>
);
}
if (!this.props.userFetched){
return <LoadingComponent
if (!userFetched) {
return (
<LoadingComponent
title="Loading dapp..."
message=""
image_type="app"
imageType="app"
progress={90}
progress_type="indicating"
progressType="indicating"
/>
);
}
return Children.only(this.props.children);
return Children.only(children);
}
}
@ -130,7 +161,7 @@ const mapStateToProps = (state) => ({
accounts: state.accounts,
contractInitialized: state.contracts.Forum.initialized,
contractDeployed: state.contracts.Forum.deployed,
userFetched: state.user.address
userFetched: state.user.address,
});
export default connect(mapStateToProps)(LoadingContainer);

35
packages/concordia-app/src/components/MenuComponent.jsx

@ -1,38 +1,35 @@
import React, { Component } from 'react';
import { withRouter } from "react-router";
import React from 'react';
import { withRouter } from 'react-router';
import { Menu } from 'semantic-ui-react';
import AppContext from "./AppContext";
import AppContext from './AppContext';
import app_logo from '../assets/images/app_logo.png';
import appLogo from '../assets/images/app_logo.png';
import SignUpForm from './SignUpForm';
class MenuComponent extends Component {
render() {
const MenuComponent = (props) => {
const { history: { push } } = props;
return (
<AppContext.Consumer>
{context => {
return(
{() => (
<div>
<Menu color='black' inverted>
<Menu color="black" inverted>
<Menu.Item
link
name='home'
onClick={() => { this.props.history.push("/"); }}
name="home"
onClick={() => { push('/'); }}
>
<img src={app_logo} alt="app_logo"/>
<img src={appLogo} alt="app_logo" />
</Menu.Item>
<SignUpForm/>
<SignUpForm />
</Menu>
</div>
)
}
}
)}
</AppContext.Consumer>
)
}
}
);
};
export default withRouter(MenuComponent);

69
packages/concordia-app/src/components/SignUpForm.jsx

@ -1,8 +1,10 @@
import React, { Component } from 'react';
import { Button, Form, Menu, Message, Modal } from 'semantic-ui-react';
import {
Button, Form, Menu, Message, Modal,
} from 'semantic-ui-react';
import AppContext from "./AppContext";
import { connect } from 'react-redux';
import AppContext from './AppContext';
const contractName = 'Forum';
const checkUsernameTakenMethod = 'isUserNameTaken';
@ -30,22 +32,8 @@ class SignUpForm extends Component {
};
}
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,
);
}
componentDidUpdate() {
// TODO
}
handleSubmit() {
@ -67,8 +55,22 @@ class SignUpForm extends Component {
}
}
componentDidUpdate() {
// TODO
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,
);
}
}
completeAction() {
@ -76,8 +78,8 @@ class SignUpForm extends Component {
const { user, account } = this.props;
if (user.hasSignedUp) {
console.log('Signing up..')
this.contract.methods['signUp'].cacheSend(usernameInput);
console.log('Signing up..');
this.contract.methods.signUp.cacheSend(usernameInput);
} else {
this.setState({
signingUp: true,
@ -96,21 +98,25 @@ class SignUpForm extends Component {
error, usernameInput, errorHeader, errorMessage, signingUp,
} = this.state;
return(
<Modal as={Form} onSubmit={e => this.handleSubmit(e)} trigger={
return (
<Modal
as={Form}
onSubmit={(e) => this.handleSubmit(e)}
trigger={(
<Menu.Item
name='signup'
position='right'
content='Sign Up'
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'
placeholder="Username"
name="usernameInput"
value={usernameInput}
onChange={this.handleInputChange}
@ -125,15 +131,14 @@ class SignUpForm extends Component {
</Modal.Content>
</Modal>
)
);
}
}
SignUpForm.contextType = AppContext.Context;
const mapStateToProps = (state) => ({
user: state.user
user: state.user,
});
export default connect(mapStateToProps)(SignUpForm);

13
packages/concordia-app/src/index.js → packages/concordia-app/src/index.jsx

@ -1,11 +1,11 @@
import React from 'react';
import { render } from 'react-dom';
import App from './components/App'
import { Drizzle } from '@ezerous/drizzle';
import { Breeze } from '@ezerous/breeze';
import App from './components/App';
import store from './redux/store';
import { Drizzle } from '@ezerous/drizzle'
import { Breeze } from '@ezerous/breeze'
import AppContext from "./components/AppContext";
import AppContext from './components/AppContext';
import drizzleOptions from './options/drizzleOptions';
import * as serviceWorker from './utils/serviceWorker';
@ -20,10 +20,7 @@ render(
<AppContext.Provider drizzle={drizzle} breeze={breeze}>
<App store={store} />
</AppContext.Provider>,
document.getElementById('root')
document.getElementById('root'),
);
serviceWorker.unregister(); // See also: http://bit.ly/CRA-PWA

22
packages/concordia-app/src/options/breezeOptions.js

@ -1,6 +1,6 @@
import { orbitConstants } from '@ezerous/breeze';
import web3Options from './web3Options';
import EthereumIdentityProvider from '../orbit/ΕthereumIdentityProvider';
import { orbitConstants } from '@ezerous/breeze'
const { web3 } = web3Options;
EthereumIdentityProvider.setWeb3(web3);
@ -12,34 +12,34 @@ const breezeOptions = {
Swarm: [
// Use local signaling server (see also rendezvous script in package.json)
// For more information: https://github.com/libp2p/js-libp2p-webrtc-star
'/ip4/127.0.0.1/tcp/9090/wss/p2p-webrtc-star'
'/ip4/127.0.0.1/tcp/9090/wss/p2p-webrtc-star',
// Use the following public servers if needed
// '/dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star',
// '/dns4/ wrtc-star2.sjc.dwebops.pub/tcp/443/wss/p2p-webrtc-star'
]
],
},
},
preload: {
enabled: false
enabled: false,
},
init: {
emptyRepo: true
}
emptyRepo: true,
},
},
orbit: {
identityProvider: EthereumIdentityProvider,
databases: [
{
name: 'topics',
type: orbitConstants.ORBIT_TYPE_KEYVALUE
type: orbitConstants.ORBIT_TYPE_KEYVALUE,
},
{
name: 'posts',
type: orbitConstants.ORBIT_TYPE_KEYVALUE
}
]
}
type: orbitConstants.ORBIT_TYPE_KEYVALUE,
},
],
},
};
export default breezeOptions;

6
packages/concordia-app/src/options/drizzleOptions.js

@ -4,14 +4,14 @@ import web3Options from './web3Options';
const drizzleOptions = {
web3: {
customProvider: web3Options.web3
customProvider: web3Options.web3,
},
contracts,
events: {
Forum: ['UserSignedUp', 'UsernameUpdated', 'TopicCreated', 'PostCreated']
Forum: ['UserSignedUp', 'UsernameUpdated', 'TopicCreated', 'PostCreated'],
},
reloadWindowOnNetworkChange: true,
reloadWindowOnAccountChange: true // We need it to reinitialize breeze and create new Orbit databases
reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases
};
export default drizzleOptions;

2
packages/concordia-app/src/options/web3Options.js

@ -8,7 +8,7 @@ const web3 = new Web3(Web3.givenProvider || `ws://${WEB3_URL}:${WEB3_PORT}`);
EthereumIdentityProvider.setWeb3(web3);
const web3Options = {
web3
web3,
};
export default web3Options;

6
packages/concordia-app/src/orbit/orbitUtils.js

@ -1,7 +1,11 @@
// https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#address
export async function determineDBAddress({orbit, dbName, type, identityId}) {
async function determineDBAddress({
orbit, dbName, type, identityId,
}) {
const ipfsMultihash = (await orbit.determineAddress(dbName, type, {
accessController: { write: [identityId] },
})).root;
return `/orbitdb/${ipfsMultihash}/${dbName}`;
}
export default determineDBAddress;

72
packages/concordia-app/src/orbit/ΕthereumIdentityProvider.js

@ -1,23 +1,24 @@
/* eslint-disable no-console */
/* eslint-disable no-return-await */
import IdentityProvider from 'orbit-db-identity-provider';
import { getIdentitySignaturePubKey, storeIdentitySignaturePubKey } from './levelUtils';
import IdentityProvider from "orbit-db-identity-provider";
const LOGGING_PREFIX = 'EthereumIdentityProvider: ';
class EthereumIdentityProvider extends IdentityProvider{
class EthereumIdentityProvider extends IdentityProvider {
constructor(options = {}) {
if(!EthereumIdentityProvider.web3)
throw new Error(LOGGING_PREFIX + "Couldn't create identity, because web3 wasn't set. " +
"Please use setWeb3(web3) first!");
if (!EthereumIdentityProvider.web3) {
throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because web3 wasn't set. `
+ 'Please use setWeb3(web3) first!');
}
super(options);
// Orbit's Identity Id (user's Ethereum address) - Optional (will be grabbed later if omitted)
const id = options.id;
if(id){
if(EthereumIdentityProvider.web3.utils.isAddress(id))
this.id = options.id;
else
throw new Error(LOGGING_PREFIX + "Couldn't create identity, because an invalid id was supplied.");
const { id } = options;
if (id) {
if (EthereumIdentityProvider.web3.utils.isAddress(id)) this.id = options.id;
else throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because an invalid id was supplied.`);
}
}
@ -25,19 +26,21 @@ class EthereumIdentityProvider extends IdentityProvider{
async getId() {
// Id wasn't in the constructor, grab it now
if(!this.id) {
if (!this.id) {
const accounts = await EthereumIdentityProvider.web3.eth.getAccounts();
if(!accounts[0])
throw new Error(LOGGING_PREFIX + "Couldn't create identity, because no web3 accounts were found (locked Metamask?).");
if (!accounts[0]) {
throw new Error(`${LOGGING_PREFIX}Couldn't create identity, because no web3 accounts were found (
locked Metamask?).`);
}
this.id = accounts[0];
[this.id] = accounts;
}
return this.id;
}
async signIdentity(data) {
if (process.env.NODE_ENV === 'development') { //Don't sign repeatedly while in development
console.debug(LOGGING_PREFIX + 'Attempting to find stored Orbit identity data...');
if (process.env.NODE_ENV === 'development') { // Don't sign repeatedly while in development
console.debug(`${LOGGING_PREFIX}Attempting to find stored Orbit identity data...`);
const signaturePubKey = await getIdentitySignaturePubKey(data);
if (signaturePubKey) {
const identityInfo = {
@ -46,59 +49,58 @@ class EthereumIdentityProvider extends IdentityProvider{
signaturePubKey,
};
if (await EthereumIdentityProvider.verifyIdentityInfo(identityInfo)) {
console.debug(LOGGING_PREFIX + 'Found and verified stored Orbit identity data!');
console.debug(`${LOGGING_PREFIX}Found and verified stored Orbit identity data!`);
return signaturePubKey;
}
console.debug(LOGGING_PREFIX + "Stored Orbit identity data couldn't be verified.");
} else
console.debug(LOGGING_PREFIX + 'No stored Orbit identity data were found.');
console.debug(`${LOGGING_PREFIX}Stored Orbit identity data couldn't be verified.`);
} else console.debug(`${LOGGING_PREFIX}No stored Orbit identity data were found.`);
}
return await this.doSignIdentity(data);
}
// eslint-disable-next-line consistent-return
async doSignIdentity(data) {
try {
const signaturePubKey = await EthereumIdentityProvider.web3.eth.personal.sign(data, this.id, '');
if (process.env.NODE_ENV === 'development') {
storeIdentitySignaturePubKey(data, signaturePubKey)
.then(() => {
console.debug(LOGGING_PREFIX + 'Successfully stored current Orbit identity data.');
console.debug(`${LOGGING_PREFIX}Successfully stored current Orbit identity data.`);
})
.catch(() => {
console.warn(LOGGING_PREFIX + "Couldn't store current Orbit identity data...");
console.warn(`${LOGGING_PREFIX}Couldn't store current Orbit identity data...`);
});
}
return signaturePubKey; // Password not required for MetaMask
} catch (error) {
if(error.code && error.code === 4001){
console.debug(LOGGING_PREFIX + 'User denied message signature.');
if (error.code && error.code === 4001) {
console.debug(`${LOGGING_PREFIX}User denied message signature.`);
return await this.doSignIdentity(data);
}
else{
console.error(LOGGING_PREFIX + 'Failed to sign data.');
console.error(`${LOGGING_PREFIX}Failed to sign data.`);
console.error(error);
}
}
}
static async verifyIdentity(identity) {
// Verify that identity was signed by the ID
return new Promise(resolve => {
return new Promise((resolve) => {
resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identity.publicKey + identity.signatures.id,
identity.signatures.publicKey) === identity.id)
})
identity.signatures.publicKey) === identity.id);
});
}
static async verifyIdentityInfo(identityInfo) {
// Verify that identity was signed by the ID
return new Promise(resolve => {
return new Promise((resolve) => {
resolve(EthereumIdentityProvider.web3.eth.accounts.recover(identityInfo.pubKeySignId,
identityInfo.signaturePubKey) === identityInfo.id)
})
identityInfo.signaturePubKey) === identityInfo.id);
});
}
// Initialize by supplying a web3 object
static setWeb3(web3){
static setWeb3(web3) {
EthereumIdentityProvider.web3 = web3;
}
}

8
packages/concordia-app/src/redux/reducers/userReducer.js

@ -9,12 +9,12 @@ const initialState = {
const userReducer = (state = initialState, action) => {
const { type } = action;
if(type === USER_DATA_UPDATED) {
if (type === USER_DATA_UPDATED) {
const { address, username } = action;
if(username){
if (username) {
return {
username: username,
address: address,
username,
address,
hasSignedUp: true,
};
}

21
packages/concordia-app/src/redux/sagas/orbitSaga.js

@ -1,22 +1,21 @@
import { put, all, take } from 'redux-saga/effects'
import { put, all, take } from 'redux-saga/effects';
import { breezeActions } from '@ezerous/breeze'
import { drizzleActions } from '@ezerous/drizzle'
import { breezeActions } from '@ezerous/breeze';
import { drizzleActions } from '@ezerous/drizzle';
function * initOrbitDatabases (action) {
const { account, breeze} = action;
yield put(breezeActions.orbit.orbitInit(breeze, account)); //same as breeze.initOrbit(account);
function* initOrbitDatabases(action) {
const { account, breeze } = action;
yield put(breezeActions.orbit.orbitInit(breeze, account)); // same as breeze.initOrbit(account);
}
function * orbitSaga () {
function* orbitSaga() {
const res = yield all([
take(drizzleActions.drizzle.DRIZZLE_INITIALIZED),
take(breezeActions.breeze.BREEZE_INITIALIZED),
take(drizzleActions.account.ACCOUNTS_FETCHED)
take(drizzleActions.account.ACCOUNTS_FETCHED),
]);
yield initOrbitDatabases({breeze:res[1].breeze, account: res[2].accounts[0]});
yield initOrbitDatabases({ breeze: res[1].breeze, account: res[2].accounts[0] });
}
export default orbitSaga
export default orbitSaga;

8
packages/concordia-app/src/redux/sagas/rootSaga.js

@ -1,15 +1,15 @@
import { all, fork } from 'redux-saga/effects';
import { drizzleSagas } from '@ezerous/drizzle';
import { breezeSagas } from '@ezerous/breeze'
import orbitSaga from './orbitSaga'
import userSaga from './userSaga'
import { breezeSagas } from '@ezerous/breeze';
import orbitSaga from './orbitSaga';
import userSaga from './userSaga';
export default function* root() {
const sagas = [
...drizzleSagas,
...breezeSagas,
orbitSaga,
userSaga
userSaga,
];
yield all(
sagas.map((saga) => fork(saga)),

23
packages/concordia-app/src/redux/sagas/userSaga.js

@ -1,10 +1,13 @@
import { all, call, put, take } from 'redux-saga/effects';
/* eslint-disable no-console */
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'];
function* fetchUserData({ drizzle, account }) {
const contract = drizzle.contracts.Forum;
const transaction = yield call(contract.methods.hasUserSignedUp, account);
try {
@ -15,28 +18,26 @@ function * fetchUserData ({drizzle, account}) {
if (callResult) {
const txObj2 = yield call(contract.methods.getUsername, account);
dispatchArgs.username = yield call(txObj2.call, {
address: account
address: account,
});
}
yield put({
type: USER_DATA_UPDATED, ...dispatchArgs
type: USER_DATA_UPDATED, ...dispatchArgs,
});
} catch (error) {
console.error(error);
yield put({ type: USER_DATA_ERROR });
}
}
function * userSaga () {
function* userSaga() {
const res = yield all([
take(drizzleActions.drizzle.DRIZZLE_INITIALIZED),
take(drizzleActions.account.ACCOUNTS_FETCHED)
take(drizzleActions.account.ACCOUNTS_FETCHED),
]);
yield fetchUserData({drizzle:res[0].drizzle, account: res[1].accounts[0]});
yield fetchUserData({ drizzle: res[0].drizzle, account: res[1].accounts[0] });
}
export default userSaga
export default userSaga;

13
packages/concordia-app/src/redux/store.js

@ -1,8 +1,8 @@
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { drizzleReducers, drizzleMiddlewares, generateContractsInitialState } from '@ezerous/drizzle';
import { breezeReducers } from '@ezerous/breeze'
import userReducer from './reducers/userReducer'
import { breezeReducers } from '@ezerous/breeze';
import createSagaMiddleware from 'redux-saga';
import userReducer from './reducers/userReducer';
import rootSaga from './sagas/rootSaga';
import drizzleOptions from '../options/drizzleOptions';
@ -13,12 +13,13 @@ const initialState = {
const sagaMiddleware = createSagaMiddleware();
const store = configureStore({
reducer: {...drizzleReducers, ...breezeReducers, user: userReducer },
reducer: { ...drizzleReducers, ...breezeReducers, user: userReducer },
middleware: getDefaultMiddleware({
serializableCheck: false, //https://redux.js.org/style-guide/style-guide/#do-not-put-non-serializable-values-in-state-or-actions
// https://redux.js.org/style-guide/style-guide/#do-not-put-non-serializable-values-in-state-or-actions
serializableCheck: false,
}).concat(drizzleMiddlewares).concat(sagaMiddleware),
preloadedState: initialState
})
preloadedState: initialState,
});
sagaMiddleware.run(rootSaga);
export default store;

38
packages/concordia-app/src/utils/serviceWorker.js

@ -1,3 +1,6 @@
/* eslint-disable no-console */
/* eslint-disable no-use-before-define */
// This optional code is used to register a service worker.
// register() is not called by default.
@ -11,13 +14,13 @@
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
window.location.hostname === 'localhost'
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
|| 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}$/
)
|| window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
),
);
export function register(config) {
@ -42,8 +45,8 @@ export function register(config) {
// 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://bit.ly/CRA-PWA'
'This web app is being served cache-first by a service '
+ 'worker. To learn more, visit https://bit.ly/CRA-PWA',
);
});
} else {
@ -57,7 +60,8 @@ export function register(config) {
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
.then((registration) => {
// eslint-disable-next-line no-param-reassign
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
@ -70,8 +74,8 @@ function registerValidSW(swUrl, config) {
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
'New content is available and will be used when all '
+ 'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
);
// Execute callback
@ -93,7 +97,7 @@ function registerValidSW(swUrl, config) {
};
};
})
.catch(error => {
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
@ -101,15 +105,15 @@ function registerValidSW(swUrl, config) {
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
response.status === 404
|| (contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
@ -121,14 +125,14 @@ function checkValidServiceWorker(swUrl, config) {
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
'No internet connection found. App is running in offline mode.',
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}

Loading…
Cancel
Save