-
-
Save loganpowell/087fe422ebc90706dbf7d1644540050c to your computer and use it in GitHub Desktop.
ClojureScript & React sample code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* next add the state to ask security questions */ | |
render: function(){ | |
// Now add the security challenge state | |
var item = null; | |
switch(this.state.bankState){ | |
case "CONNECTED": | |
break; | |
case "SECURITY": | |
// create a new element to show questions and get answers | |
item = el('BankItemSecurity', { | |
bank: this.props.bank, | |
challenges: this.state.securityChallenge, | |
onAnswered: this.state.securityPass | |
}); | |
break; | |
case "AUTHENTICATION": | |
// create a new element to ask for username/password | |
item = el('BankItemAuthentication', { | |
bank:this.props.bank, | |
onConnect:this._link | |
}); | |
break; | |
} | |
// creates the HTML to show the view | |
return el('div', null, | |
el('h2', null, bank.name), | |
item); | |
}, | |
_link: function(username, password){ | |
// when clojurescript is ready for the user/pass, it will call this function | |
var authenticate = function(request){ | |
// return a promise that resolves right away with the user/pass | |
return new Promise(function(resolve){ | |
resolve({username:username, password:password}); | |
}); | |
}; | |
// if clojurescript needs to ask security questions, it will call this function | |
var challenge = function(request){ | |
// get the questions and return a promise to clojurescript | |
return new Promise(function(resolve, reject){ | |
this.setState({ | |
state: "SECURITY", | |
securityChallenge: request.questions, | |
securityPass: resolve, // once the user gives the anwser, the resolve will send it to cljs | |
securityFail: reject | |
}); | |
}); | |
}; | |
// call clojurescript and pass in the auth and chanllege and get a promise | |
this.context.triforce | |
.bank_link(authenticate, challenge) | |
.then(function(response){ | |
// when clojurescript is successfully connected the bank, set the state and render the view | |
this.setState({ | |
accounts: response, | |
state: "CONNECTED" | |
}); | |
}) | |
.catch(function(err){ | |
this.setState({ | |
securityChallenge: {}, | |
securityPass: noop, | |
securityFail: noop}); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* at last we'll add the Connected state */ | |
// when this element starts, we'll add a callback to clojurescript to know when anything changes on the accounts | |
componentWillMount: function(){ | |
// simple filter function so we only get accounts for this bank | |
var myAccountsFilter = function(account){ | |
return account.bankId === this.props.bank.id; | |
}; | |
// whenever anything changes on any account, it will trigger this callback | |
var onChanged = function(accounts){ | |
// if there are accounts for this bank then we know it's connected | |
var newState = {accounts: accounts}; | |
if (accounts.length > 0){ | |
newState.state = "CONNECTED"; | |
} | |
// set the state and trigger the render function | |
this.setState({accounts: newState}); | |
}; | |
// pass our callback into clojurescript | |
this.context.triforce.accounts(myAccountsFilter, onChanged); | |
}, | |
render: function(){ | |
// when an account is checked/unchecked, send it to clojurescript | |
var changeActive = function(accountId, isActive){ | |
// we could use the promise it returns, but it's better to just let the | |
// callback we created in the componentWillMount handle it | |
this.context.triforce.bank_account_active(accountId, isActive); | |
}; | |
// Add the last state of connected to show all the accounts | |
var item = null; | |
switch(this.state.bankState){ | |
case "CONNECTED": | |
// create a new element to show accounts | |
item = el('BankItemConnected', { | |
bank: this.props.bank, | |
accounts: this.state.accounts, | |
onActiveChange: changeActive | |
}); | |
break; | |
case "SECURITY": | |
item = el('BankItemSecurity', { | |
bank: this.props.bank, | |
challenges: this.state.securityChallenge, | |
onAnswered: this.state.securityPass | |
}); | |
break; | |
case "AUTHENTICATION": | |
item = el('BankItemAuthentication', { | |
bank:this.props.bank, | |
onConnect:this._link | |
}); | |
break; | |
} | |
// creates the HTML to show the view | |
return el('div', null, | |
el('h2', null, bank.name), | |
item); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
createView({ | |
contextTypes: { | |
triforce: React.PropTypes.object.isRequired | |
}, | |
getDefaultProps: function(){ | |
return {bank: {}}; | |
}, | |
getInitialState: function(){ | |
return { | |
state: "AUTHENTICATION", | |
accounts: [], | |
securityChallenge: {}, | |
securityPass: noop, | |
securityFail: noop}; | |
}, | |
componentWillMount: function(){ | |
var myAccountsFilter = function(account){ | |
return account.bankId === this.props.bank.id; | |
}; | |
var onChanged = function(accounts){ | |
var newState = {accounts: accounts}; | |
if (accounts.length > 0){ | |
newState.state = "CONNECTED"; | |
} | |
this.setState({accounts: newState}); | |
}; | |
this.context.triforce.accounts(myAccountsFilter, onChanged); | |
}, | |
render: function(){ | |
var changeActive = function(accountId, isActive){ | |
this.context.triforce.bank_account_active(accountId, isActive); | |
}; | |
var item = null; | |
switch(this.state.bankState){ | |
case "CONNECTED": | |
item = el('BankItemConnected', { | |
bank: this.props.bank, | |
accounts: this.state.accounts, | |
onActiveChange: changeActive | |
}); | |
break; | |
case "SECURITY": | |
item = el('BankItemSecurity', { | |
bank: this.props.bank, | |
challenges: this.state.securityChallenge, | |
onAnswered: this.state.securityPass | |
}); | |
break; | |
case "AUTHENTICATION": | |
item = el('BankItemAuthentication', { | |
bank:this.props.bank, | |
onConnect:this._link | |
}); | |
break; | |
} | |
return el('div', null, | |
el('h2', null, bank.name), | |
item); | |
}, | |
_link: function(username, password){ | |
var authenticate = function(request){ | |
return new Promise(function(resolve){ | |
resolve({username:username, password:password}); | |
}); | |
}; | |
var challenge = function(request){ | |
return new Promise(function(resolve, reject){ | |
this.setState({ | |
state: "SECURITY", | |
securityChallenge: request.questions, | |
securityPass: resolve, | |
securityFail: reject | |
}); | |
}); | |
}; | |
this.context.triforce | |
.bank_link(authenticate, challenge) | |
.then(function(response){ | |
this.setState({ | |
accounts: response, | |
state: "CONNECTED" | |
}); | |
}) | |
.catch(function(err){ | |
this.setState({ | |
securityChallenge: {}, | |
securityPass: noop, | |
securityFail: noop}); | |
}); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Create a basic class to show a list of banks */ | |
var el = React.createElement; | |
var createView = React.createClass; | |
var noop = function(){}; | |
createView({ | |
// if the parent element doesn't pass a selectedIds, then use this instead | |
getDefaultProps: function(){ | |
return {selectedIds: [1, 10]}; | |
}, | |
// when first created have an empty array that will hold the bank objects | |
getInitialState: function(){ | |
return {banks: []}; | |
}, | |
// anytime the state changes (via this.setState()) it triggers this render | |
render: function(){ | |
// this will create the HTML that will show the selected banks | |
return el('div', null, | |
el('h1', null, "Bank Link @ " + this.props.route.path), | |
el('a', {href:"/install"}, "Download App")); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* connect the view to clojurescript to show the list of banks */ | |
// triforce is our clojurescript library. It initializes once and "smart" components ask to use it like this: | |
contextTypes: { | |
triforce: React.PropTypes.object.isRequired | |
}, | |
// componentWillMount is only called once, when this element is first created | |
componentWillMount: function(){ | |
// get the list of banks from clojurescript, which returns a promise | |
this.context.triforce.bank_list().then(function(banks){ | |
// when the promise completes, filter out only the banks selected | |
var selectedBanks = banks.filter(function(bank){ | |
return this.props.selectedIds.indexOf(bank.id) > -1; | |
}); | |
// tell React to change the state to have the complete bank objects | |
this.setState({banks: selectedBanks}); | |
}); | |
}, | |
// anytime the state changes (via this.setState()) it triggers render | |
render: function(){ | |
// for each bank object, create an element called BankItem | |
var bankItems = this.state.banks.map(function(bank, index){ | |
// BankItem is the class we'll talk about next | |
return el('BankItem', {key:index, bank:bank}); | |
}); | |
// this will create the HTML that will show the selected banks | |
return el('div', null, | |
el('h1', null, "Bank Link @ " + this.props.route.path), | |
bankItems, | |
el('a', {href:"/install"}, "Download App")); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var el = React.createElement; | |
var createView = React.createClass; | |
createView({ | |
contextTypes: { | |
triforce: React.PropTypes.object.isRequired, | |
}, | |
getDefaultProps: function(){ | |
return {selectedIds: [1, 10]}; | |
}, | |
getInitialState: function(){ | |
return {banks: []}; | |
}, | |
componentWillMount: function(){ | |
this.context.triforce.bank_list().then(function(banks){ | |
var selectedBanks = banks.filter(function(bank){ | |
return this.props.selectedIds.indexOf(bank.id) > -1; | |
}); | |
this.setState({banks: selectedBanks}); | |
}); | |
}, | |
render: function(){ | |
var bankItems = this.state.banks.map(function(bank, index){ | |
return el('BankItem', {key:index, bank:bank}); | |
}); | |
return el('div', null, | |
el('h1', null, "Bank Link @ " + this.props.route.path), | |
bankItems, | |
el('a', {href:"/install"}, "Download App")); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Basic element to show the state of a single bank connection */ | |
createView({ | |
contextTypes: { | |
triforce: React.PropTypes.object.isRequired | |
}, | |
getDefaultProps: function(){ | |
return {bank: {}}; | |
}, | |
getInitialState: function(){ | |
return { | |
state: "AUTHENTICATION", | |
accounts: [], | |
securityChallenge: {}, | |
securityPass: noop, | |
securityFail: noop}; | |
}, | |
render: function(){ | |
// There are 3 possible states to bank linking, | |
// 1. asking for user/pass | |
// 2. needs additional security questions | |
// 3. connected bank and can choose to have account active or not | |
var item = null; | |
switch(this.state.bankState){ | |
case "CONNECTED": | |
break; | |
case "SECURITY": | |
break; | |
case "AUTHENTICATION": | |
// create a new element to ask for username/password | |
item = el('BankItemAuthentication', { | |
bank:this.props.bank, | |
onConnect:this._link | |
}); | |
break; | |
} | |
// creates the HTML to show the view | |
return el('div', null, | |
el('h2', null, bank.name), | |
item); | |
}, | |
_link: function(username, password){ | |
// when clojurescript is ready for the user/pass, it will call this function | |
var authenticate = function(request){ | |
// return a promise that resolves right away with the user/pass | |
return new Promise(function(resolve){ | |
resolve({username:username, password:password}); | |
}); | |
}; | |
// call clojurescript and pass in the auth and chanllege and get a promise | |
this.context.triforce | |
.bank_link(authenticate) | |
.then(function(response){ | |
// when clojurescript is successfully connected the bank, set the state and render the view | |
this.setState({ | |
accounts: response, | |
state: "CONNECTED" | |
}); | |
}) | |
.catch(function(err){ | |
this.setState({ | |
securityChallenge: {}, | |
securityPass: noop, | |
securityFail: noop}); | |
}); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment