diff --git a/app/src/containers/CoreLayoutContainer.js b/app/src/containers/CoreLayoutContainer.js index 7e61ab9..159ba92 100644 --- a/app/src/containers/CoreLayoutContainer.js +++ b/app/src/containers/CoreLayoutContainer.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import NavBarContainer from './NavBarContainer'; +import RightSideBarContainer from './TransactionsMonitorContainer'; /*import TransactionsMonitorContainer from '../../containers/TransactionsMonitorContainer';*/ // Styles @@ -33,7 +34,7 @@ class CoreLayout extends Component { diff --git a/app/src/containers/TransactionsMonitorContainer.js b/app/src/containers/TransactionsMonitorContainer.js new file mode 100644 index 0000000..5199902 --- /dev/null +++ b/app/src/containers/TransactionsMonitorContainer.js @@ -0,0 +1,113 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router-dom' + +import { Message } from 'semantic-ui-react'; + +class RightSideBar extends Component { + constructor(props, context) { + super(props); + + this.handleMessageClick = this.handleMessageClick.bind(this); + this.handleMessageDismiss = this.handleMessageDismiss.bind(this); + + this.state = { + isTransactionMessageDismissed: [] + } + } + + handleMessageClick(index) { + let transactionHash = this.props.transactionStack[index]; + if (this.props.transactions[transactionHash]) { + if (this.props.transactions[transactionHash].status === 'error') { + this.handleMessageDismiss(null, index); + } else { + if (this.props.transactions[transactionHash].receipt && + this.props.transactions[transactionHash].receipt.events) { + switch (Object.keys(this.props.transactions[transactionHash].receipt.events)[0]){ + case 'TopicCreated': + this.props.history.push("/topic/" + + this.props.transactions[transactionHash].receipt.events.TopicCreated.returnValues.topicID + ); + this.handleMessageDismiss(null, index); + break; + default: + break; + } + } + } + } + } + + handleMessageDismiss(event, messageIndex) { + if (event !== null) { + event.stopPropagation(); + } + + let isTransactionMessageDismissedShallowCopy = this.state.isTransactionMessageDismissed.slice(); + isTransactionMessageDismissedShallowCopy[messageIndex] = true; + this.setState({ + isTransactionMessageDismissed: isTransactionMessageDismissedShallowCopy + }); + } + + render() { + if (this.props.transactionStack.length === 0){ + return null; + } + + let transactionMessages = this.props.transactionStack.map((transaction, index) => { + if (this.state.isTransactionMessageDismissed[index]){ + return null; + } + + let color = 'black'; + let message = []; + message.push("New transaction has been queued and is waiting your confirmation."); + if (this.props.transactions[transaction]) { + message.push(
); + message.push("- transaction confirmed"); + } + if (this.props.transactions[transaction] && + this.props.transactions[transaction].status === 'success') { + /* Transaction completed successfully */ + message.push(
); + message.push("- transaction mined"); + color = 'green'; + message.push(
); + message.push("- transaction completed successfully"); + } else if (this.props.transactions[transaction] && + this.props.transactions[transaction].status === "error"){ + /* Transaction failed to complete */ + message.push(
); + message.push("- transaction mined"); + color = 'red'; + message.push(
); + message.push("Transaction failed to complete!"); + } + + return ( +
{this.handleMessageClick(index)}} > + {this.handleMessageDismiss(e, index)}}> + {message} + +
+ ); + }); + + return (transactionMessages); + } +} + +const mapStateToProps = state => { + return { + transactions: state.transactions, + transactionStack: state.transactionStack + } +}; + +const RightSideBarContainer = withRouter(connect(mapStateToProps)(RightSideBar)); + +export default RightSideBarContainer; \ No newline at end of file diff --git a/app/src/redux/actions/transactionsActions.js b/app/src/redux/actions/transactionsActions.js index 35bd009..8a2e04a 100644 --- a/app/src/redux/actions/transactionsActions.js +++ b/app/src/redux/actions/transactionsActions.js @@ -1,5 +1,4 @@ //Action creators -import uuid from 'uuid/v1'; export const INIT_TRANSACTION = 'INIT_TRANSACTION'; export const UPDATE_TRANSACTION = 'UPDATE_TRANSACTION'; @@ -14,7 +13,6 @@ export function updateUsername(newUsername, callback){ params: [newUsername], event: 'UsernameUpdated' }, - uid: uuid(), callback: callback }; } @@ -29,7 +27,6 @@ export function createTopic(userInputs){ params: [], event: 'TopicCreated' }, - uid: uuid(), userInputs: userInputs }; } @@ -44,7 +41,6 @@ export function createPost(topicID, userInputs){ params: [topicID], event: 'PostCreated' }, - uid: uuid(), userInputs: userInputs }; } @@ -52,7 +48,6 @@ export function createPost(topicID, userInputs){ export function updateTransaction(transactionIndex, updateDescriptor){ return { type: UPDATE_TRANSACTION, - index: transactionIndex, transactionUpdates: updateDescriptor }; } \ No newline at end of file diff --git a/app/src/redux/reducers/transactionsReducer.js b/app/src/redux/reducers/transactionsReducer.js deleted file mode 100644 index 5a934b2..0000000 --- a/app/src/redux/reducers/transactionsReducer.js +++ /dev/null @@ -1,39 +0,0 @@ -import { INIT_TRANSACTION, UPDATE_TRANSACTION } from '../actions/transactionsMonitorActions'; - -const initialState = { - transactions: Object.create(null) -}; - -const transactionsReducer = (state = initialState, action) => { - switch (action.type) { - case INIT_TRANSACTION: - let transactionsShallowCopy = state.transactions.slice(); - transactionsShallowCopy.push({ - status: 'initialized', - contract: action.transactionDescriptor.contract, - method: action.transactionDescriptor.method, - params: action.transactionDescriptor.params, - event: action.transactionDescriptor.event, - returnData: null, - userInputs: action.userInputs - }); - return { - transactions: transactionsShallowCopy - }; - case UPDATE_TRANSACTION: - return { transactions: state.transactions.map( (transaction, index) => { - if (index !== action.index){ - return transaction; - } - - return { - ...transaction, - ...action.transactionUpdates - } - })}; - default: - return state; - } -}; - -export default transactionsReducer; \ No newline at end of file diff --git a/app/src/redux/sagas/transactionsSaga.js b/app/src/redux/sagas/transactionsSaga.js index 15c494c..499b55f 100644 --- a/app/src/redux/sagas/transactionsSaga.js +++ b/app/src/redux/sagas/transactionsSaga.js @@ -1,36 +1,59 @@ -import {call, put, select, take, takeEvery} from 'redux-saga/effects' -import { contract, getCurrentAccount } from './drizzleUtilsSaga'; +import {call, select, take, takeEvery} from 'redux-saga/effects' import { drizzle } from '../../index' let transactionsHistory = Object.create(null); function* initTransaction(action) { - transactionsHistory[action.uid] = action; - transactionsHistory[action.uid].dataKey = drizzle.contracts[action.transactionDescriptor.contract] - .methods[action.transactionDescriptor['method']] - .cacheSend(...[action.transactionDescriptor.params]); + var dataKey = drizzle.contracts[action.transactionDescriptor.contract] + .methods[action.transactionDescriptor['method']] + .cacheSend(...[action.transactionDescriptor.params]); - transactionsHistory[action.uid].state = 'initialized'; + transactionsHistory[dataKey] = action; } -function* completeWithOrbitInteractions(action) { - const orbit = yield select((state) => state.orbit); - - yield call(orbit.topicsDB.put, action.receipt.events['TopicCreated'].returnValues.topicID, { - subject: 'tada' - }); +function* handleEvent(action) { + switch(action.event.event) { + case 'TopicCreated': + var transactionStack = yield select((state) => state.transactionStack); + var dataKey = transactionStack.indexOf(action.event.transactionHash); + if (dataKey !== -1 && + transactionsHistory[dataKey] && + transactionsHistory[dataKey].state === 'initialized') { + //Gets orbit + const orbit = yield select((state) => state.orbit); + //And saves the topic + /*yield call(orbit.topicsDB.put, ...[action.event.returnValues.topicID, { + subject: transactionsHistory[dataKey].userInputs.topicSubject + }]); + yield call(orbit.postsDB.put, ...[action.event.returnValues.postID, { + subject: transactionsHistory[dataKey].userInputs.topicSubject, + content: transactionsHistory[dataKey].userInputs.topicMessage + }]);*/ + + transactionsHistory[dataKey].state = 'success'; + } + break; + default: + //Nothing to do here + return; + } +} - yield call(orbit.postsDB.put, action.receipt.events['TopicCreated'].returnValues.postID, { - subject: 'tada', - content: 'it worked!' - }); +function* handleError() { + var transactionStack = yield select((state) => state.transactionStack); + transactionStack.forEach((transaction, index) => { + if (transaction.startsWith('TEMP_')) { + transactionsHistory[index].state = 'error'; + } + }) } function* transactionsSaga() { yield take("DRIZZLE_UTILS_SAGA_INITIALIZED"); yield takeEvery("INIT_TRANSACTION", initTransaction); - yield takeEvery("TX_SUCCESSFUL", completeWithOrbitInteractions); + yield takeEvery("EVENT_FIRED", handleEvent); + yield takeEvery("TX_ERROR", handleError); } export default transactionsSaga;