Skip to content

Instantly share code, notes, and snippets.

@stimms
Created February 3, 2015 13:39
Show Gist options
  • Save stimms/bae36ad20470cb65d63a to your computer and use it in GitHub Desktop.
Save stimms/bae36ad20470cb65d63a to your computer and use it in GitHub Desktop.
Code review of React.js
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.Actions = Marty.createActionCreators({
list: Prime.BHAComponents.Events.List(),
receiveComponents: Prime.BHAComponents.Events.ReceiveComponents(),
fetchCandidates: Prime.BHAComponents.Events.FetchCandidates(),
receiveCandidates: Prime.BHAComponents.Events.ReceiveCandidates(),
openCopyDialog: Prime.BHAComponents.Events.OpenCopyDialog(),
closeCopyDialog: Prime.BHAComponents.Events.CloseCopyDialog(),
openAddDialog: Prime.BHAComponents.Events.OpenAddDialog(),
closeAddDialog: Prime.BHAComponents.Events.CloseAddDialog(),
setCopySource: Prime.BHAComponents.Events.SetCopySource(),
copy: Prime.BHAComponents.Events.Copy(),
copyFailure: Prime.BHAComponents.Events.CopyFailure(),
fetchAvailableComponents: Prime.BHAComponents.Events.FetchAvailableComponents(),
receiveAvailableComponents: Prime.BHAComponents.Events.ReceiveAvailableComponents(),
selectListedComponent: Prime.BHAComponents.Events.SelectListedComponent(),
selectUnlistedComponent: Prime.BHAComponents.Events.SelectUnlistedComponent(),
fetchComponentDetails: Prime.BHAComponents.Events.FetchComponentDetails(),
receiveComponentDetails: Prime.BHAComponents.Events.ReceiveComponentDetails()
});
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.Index = class Index{
constructor(container, jobId, bhaId){
React.render(
/*jshint ignore:start*/
<div>
<Prime.BHAComponents.CurrentComponentsTable bhaId={bhaId} jobId={jobId}/>
<Prime.BHAComponents.NewComponentButton/>
<Prime.BHAComponents.CopyBHAButton/>
<Prime.BHAComponents.CopyBHADialog jobId={jobId} bhaId={bhaId}/>
<Prime.BHAComponents.AddDialog jobId={jobId} bhaId={bhaId}/>
</div>,
/*jshint ignore:end*/
container[0]
);
}
};
Prime.BHAComponents.NewComponentButton = React.createClass({
render: function(){
return(
/*jshint ignore:start*/
<span className="butt" onClick={this.add}>Add Components</span>
/*jshint ignore:end*/
);
},
add: function(){
Prime.BHAComponents.Actions.openAddDialog();
}
});
Prime.BHAComponents.CopyBHAButton = React.createClass({
render: function(){
return(
/*jshint ignore:start*/
<span className="butt" onClick={this.copy}>Copy BHA Components</span>
/*jshint ignore:end*/
);
},
copy: function(){
Prime.BHAComponents.Actions.openCopyDialog();
}
});
Prime.BHAComponents.CopyBHADialog = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
/*jshint ignore: start*/
if(this.state.copyDialogOpen)
{
var copyFailure;
if(this.state.copyFailure)
{
copyFailure = <div className="error">Unable to copy components as this BHA has hours assigned to it</div>;
}
return( <div className="copyDialog">
<span>Select a BHA from which to copy components</span>
{copyFailure}
<Prime.BHAComponents.CopySourceDropDown jobId={this.props.jobId} state={this.state} />
<span className="butt" onClick={this.copy}>Copy BHA Components</span>
<span className="butt" onClick={this.closeCopyDialog}>Cancel</span>
</div>);
}
return <div></div>;
/*jshint ignore: end*/
},
closeCopyDialog: function(){
Prime.BHAComponents.Actions.closeCopyDialog();
},
copy: function(){
Prime.BHAComponents.Actions.copy(this.props.bhaId);
}
});
Prime.BHAComponents.CopySourceDropDown = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
var me = this;
var body = this.state.copyCandidates.when({
pending: function(){
/*jshint ignore: start*/
return <span>Loading candidate jobs...</span>;
/*jshint ignore: end*/
},
failed: function(error){
/*jshint ignore:start*/
return <div>oh snap! {error.message}</div>;
/*jshint ignore:end*/
},
done: function(candidates){
var options = candidates.map((candidate) => {
/*jshint ignore: start*/
return <option key={candidate.id} value={candidate.id}>{candidate.name}</option>;
/*jshint ignore: end*/
});
/*jshint ignore: start*/
return <select onChange={me.updateCopySource} placeholder="Job and BHA">{options}</select>;
/*jshint ignore: end*/
},
}, this);
/*jshint ignore: start*/
return <div>{body}</div>;
/*jshint ignore: end*/
},
updateCopySource: function(e)
{
Prime.BHAComponents.Actions.setCopySource(e.currentTarget.value);
}
});
Prime.BHAComponents.AddDialog = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
/*jshint ignore: start*/
if(this.state.addDialogOpen)
return <div className="addDialog">
<Prime.BHAComponents.AddAutoComplete jobId={this.props.jobId}/>
<Prime.BHAComponents.AddUnlistedDetails />
<Prime.BHAComponents.AddListedDetails itemId={this.state.addItem.id} type={this.state.addItem.state}/>
</div>;
return <div></div>;
/*jshint ignore: end*/
}
});
Prime.BHAComponents.AddAutoComplete = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
var body = this.state.availableComponents.when({
pending:function(){
/*jshint ignore: start*/
return <div>Loading components</div>;
/*jshint ignore: end*/
},
failed: function(error){
/*jshint ignore: start*/
return <div>Unable to load components {error}</div>;
/*jshint ignore: end*/
},
done: function(){
/*jshint ignore: start*/
return <div>Serial Number:
<input type="text" className="autocomplete" name="addSerialNumber"></input>
</div>;
/*jshint ignore: end*/
}}, this);
/*jshint ignore: start*/
return <div>{body}</div>;
/*jshint ignore: end*/
},
componentDidMount: function(){
var node = $(this.getDOMNode()).find("[name=addSerialNumber]");
$.widget( "custom.catcomplete", $.ui.autocomplete, {
_create: function() {
this._super();
this.widget().menu( "option", "items", "> :not(.ui-autocomplete-category)" );
},
_renderMenu: function( ul, items ) {
var that = this,
currentCategory = "";
$.each( items, function( index, item ) {
var li;
if ( item.type != currentCategory ) {
ul.append( "<li class='ui-autocomplete-category'>" + item.type + "</li>" );
currentCategory = item.type;
}
li = that._renderItemData( ul, item );
if ( item.category ) {
li.attr( "aria-label", item.category + " : " + item.label );
}
});
}
});
node.catcomplete({source: _.sortBy(_.map(this.state.availableComponents.result, (item) =>({
'label': item.description,
'type': item.type,
'id': item.id
})), (item)=>item.type),
select: this.select,
change: this.change
});
},
select: function(event, ui){
Prime.BHAComponents.Actions.selectListedComponent(ui.item.id, ui.item.type);
},
change: function(event, ui){
if(!ui.item)
Prime.BHAComponents.Actions.selectUnlistedComponent($(event.target).val());
}
});
Prime.BHAComponents.AddListedDetails = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
/*jshint ignore: start*/
var fetchedDetails = this.state.fetchComponentDetails.when({
pending:function(){
return <div>Loading details</div>;
},
error: function(error){
return <div>Loading details error {error}</div>;
},
done: function(){
return <div>Loading details done</div>;
}
});
if(this.state.addItem.id)
return (<div>
<Prime.BHAComponents.ItemNumber/>
{fetchedDetails}
</div>);
return <div></div>;
/*jshint ignore: end*/
}
});
Prime.BHAComponents.AddUnlistedDetails = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
/*jshint ignore: start*/
if(this.state.addItem.serialNumber)
return (<div>
<Prime.BHAComponents.ItemNumber/>
<label>Type</label>
<span>{this.state.addItem.type}</span>
</div>);
return <div></div>;
/*jshint ignore: end*/
}
});
Prime.BHAComponents.ItemNumber = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
/*jshint ignore: start*/
var itemNumberOptions = this.state.components.result.map((component) => {
return <option key={component.itemNumber} value={component.itemNumber}>{component.itemNumber}</option>;
});
var finalPosition = this.state.components.result.length + 1;
itemNumberOptions.push(
<option key={finalPosition} value={finalPosition}>{finalPosition}</option>
);
return (<div>
<label>Item Number</label>
<select>{itemNumberOptions}</select>
</div>);
/*jshint ignore: end*/
}
});
Prime.BHAComponents.CurrentComponentsTable = React.createClass({
mixins: [Prime.BHAComponents.State],
render: function(){
var body = this.state.components.when({
pending: function(){
/*jshint ignore:start*/
return <div>Loading...</div>;
/*jshint ignore:end*/
},
failed: function(error){
/*jshint ignore:start*/
return <div>oh snap! {error.message}</div>;
/*jshint ignore:end*/
},
done: function(components){
return(
/*jshint ignore:start*/
<table className="tbl">
<thead>
<tr>
<th></th>
<th>Item No.</th>
<th>Type</th>
<th>Vendor</th>
<th>Description</th>
<th>Serial Number</th>
<th>OD</th>
<th>ID</th>
<th>Connection</th>
<th>Length</th>
<th>Cumulative Length</th>
<th></th>
</tr>
</thead>
<tbody>
<Prime.BHAComponents.CurrentComponentsTableRows components={components} />
</tbody>
</table>
/*jshint ignore:end*/
);
}
});
/*jshint ignore:start*/
return <div>{body}</div>;
/*jshint ignore:end*/
}
});
Prime.BHAComponents.CurrentComponentsTableRows = React.createClass({
render: function(){
var rows = this.props.components.map((component) => {
return(
/*jshint ignore:start*/
<tr key={component.id}>
<td><span className="pseudolink" onClick={this.editComponent.bind(this, component.id)}>Edit</span></td>
<td>{component.itemNumber}</td>
<td>{component.type}</td>
<td>{component.vendor}</td>
<td>{component.description}</td>
<td>{component.serialNumber}</td>
<td>{component.outerDiameter}</td>
<td>{component.innerDiameter}</td>
<td>{component.connection}</td>
<td>{component.length}</td>
<td>{component.cumulativeLength}</td>
<td><span className="pseudolink" onClick={this.deleteComponent.bind(this, component.id)}>Delete</span></td>
</tr>
/*jshint ignore:end*/
);
});
return (
/*jshint ignore:start*/
<tbody>
{rows}
</tbody>
/*jshint ignore:end*/
);
},
editComponent: function(id){
console.log("edit" + id);
},
deleteComponent: function(id){
console.log("delete" + id);
}
});
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.Events = Marty.createConstants([
"List",
"ReceiveComponents",
"FetchCandidates",
"ReceiveCandidates",
"ComponentAdded",
"ComponentMovedUp",
"ComponentMovedDown",
"ComponentRemoved",
"ComponentEdited",
"OpenCopyDialog",
"CloseCopyDialog",
"SetCopySource",
"Copy",
"CopyFailure",
"OpenAddDialog",
"CloseAddDialog",
"FetchAvailableComponents",
"ReceiveAvailableComponents",
"SelectListedComponent",
"SelectUnlistedComponent",
"FetchComponentDetails",
"ReceiveComponentDetails"
]);
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.State = Marty.createStateMixin({
listenTo: [Prime.BHAComponents.Store],
getState: function() {
return {
components: Prime.BHAComponents.Store.list(this.props.bhaId),
copyCandidates: Prime.BHAComponents.Store.fetchCandidates(this.props.jobId),
copyDialogOpen: Prime.BHAComponents.Store.state.copyDialogOpen,
copySource: Prime.BHAComponents.Store.state.copySource,
bhaId: Prime.BHAComponents.Store.state.bhaId,
copyFailure: Prime.BHAComponents.Store.state.copyFailure,
addDialogOpen: Prime.BHAComponents.Store.state.addDialogOpen,
availableComponents: Prime.BHAComponents.Store.fetchAvailableComponents(this.props.jobId),
addItem: Prime.BHAComponents.Store.state.addItem,
fetchComponentDetails: Prime.BHAComponents.Store.fetchComponentDetails(this.props.itemId, this.props.type)
};
}
});
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.StateSource = Marty.createStateSource({
type: 'http',
baseUrl: '/BHAComponents',
list: function(bhaId){
return this.get('/?bhaId=' + bhaId).then(function(res){
return Prime.BHAComponents.Actions.receiveComponents(res.body);
});
},
fetchCandidates: function(jobId)
{
return this.get("/CopyCandidates/?jobId=" + jobId).then(function(res){
return Prime.BHAComponents.Actions.receiveCandidates(res.body);
}, function(result)
{
console.log("Failure in fetching candidates");
console.dir(result);
});
},
copy: function(sourceBHAId, destinationBHAId)
{
return this.post('/copy?sourceBHAId=' + sourceBHAId + '&destinationBHAId=' + destinationBHAId).then(function(){
Prime.BHAComponents.Actions.list(destinationBHAId);
}, function(result){
Prime.BHAComponents.Actions.copyFailure();
});
},
fetchAvailableComponents: function(jobId){
return this.get("/AvailableCandidates/?jobId=" + jobId).then(function(res){
return Prime.BHAComponents.Actions.receiveAvailableComponents(res.body);
},
function(result){
console.log("Failed to fetch avaialble components");
console.dir(result);
});
},
fetchComponentDetails: function(id, type){
return this.get("/ComponentDetails/?id=" + id + "&type=" + type).then(function(res){
return Prime.BHAComponents.Actions.receiveComponentDetails(res.body);
},
function(result){
console.log("Failed to fetch component details");
console.dir(result);
});
}
});
var Prime = Prime || {};
Prime.BHAComponents = Prime.BHAComponents || {};
Prime.BHAComponents.Store = Marty.createStore({
handlers: {
list: Prime.BHAComponents.Events.List,
receiveComponents: Prime.BHAComponents.Events.ReceiveComponents,
openCopyDialog: Prime.BHAComponents.Events.OpenCopyDialog,
closeCopyDialog: Prime.BHAComponents.Events.CloseCopyDialog,
fetchCandidates: Prime.BHAComponents.Events.FetchCandidates,
receiveCandidates: Prime.BHAComponents.Events.ReceiveCandidates,
setCopySource: Prime.BHAComponents.Events.SetCopySource,
copy: Prime.BHAComponents.Events.Copy,
copyFailure: Prime.BHAComponents.Events.CopyFailure,
openAddDialog: Prime.BHAComponents.Events.OpenAddDialog,
fetchAvailableComponents: Prime.BHAComponents.Events.FetchAvailableComponents,
receiveAvailableComponents: Prime.BHAComponents.Events.ReceiveAvailableComponents,
selectListedComponent: Prime.BHAComponents.Events.SelectListedComponent,
selectUnlistedComponent: Prime.BHAComponents.Events.SelectUnlistedComponent,
fetchComponentDetails: Prime.BHAComponents.Events.FetchComponentDetails,
receiveComponentDetails: Prime.BHAComponents.Events.ReceiveComponentDetails
/*componentAdded: Prime.BHAComponents.Events.ComponentAdded,
componentMovedUp: Prime.BHAComponents.Events.ComponentMovedUp,
componentMovedDown: Prime.BHAComponents.Events.ComponentMovedDown,
componentRemoved: Prime.BHAComponents.Events.ComponentRemoved,
componentEdited: Prime.BHAComponents.Events.ComponentEdited*/
},
getInitialState: function(){
return {
components: [],
copyDialogOpen: false,
copySource: null,
bhaId: null,
copying: null,
copyFailure: false,
addDialogOpen: false,
addItem: {
id: null,
type: null,
serialNumber: null
}
};
},
list: function(bhaId){
return this.fetch({
id: 'list-components',
locally: function(){
if(this.hasAlreadyFetched('list-components') && !this.state.copying)
return this.state.components;
},
remotely: function(){
this.state.bhaId = bhaId;
this.state.copying = false;
return Prime.BHAComponents.StateSource.list(bhaId);
}
});
},
receiveComponents: function(components){
this.state.components= components;
this.hasChanged();
},
openCopyDialog: function(){
this.state.copyDialogOpen= true;
this.hasChanged();
},
closeCopyDialog: function(){
this.state.copyDialogOpen= false;
this.hasChanged();
},
setCopySource: function(sourceBHAId){
this.state.copySource = sourceBHAId;
this.hasChanged();
},
fetchCandidates: function(jobId){
return this.fetch({
id: 'fetch-candidates',
locally: function(){
if(this.hasAlreadyFetched('fetch-candidates'))
return this.state.candidates;
},
remotely: function(){
return Prime.BHAComponents.StateSource.fetchCandidates(jobId);
}
});
},
receiveCandidates: function(candidates){
this.state.candidates = candidates;
if(candidates && candidates.length>0)
this.state.copySource = candidates[0].id;
this.hasChanged();
},
fetchAvailableComponents: function(jobId){
return this.fetch({
id: 'fetch-available',
locally: function(){
if(this.hasAlreadyFetched('fetch-available'))
return this.state.availableComponents;
},
remotely: function(){
return Prime.BHAComponents.StateSource.fetchAvailableComponents(jobId);
}
});
},
receiveAvailableComponents: function(components){
this.state.availableComponents = components;
this.hasChanged();
},
copy: function(destinationBHAId){
this.state.copying = true;
var bhaId = destinationBHAId;
return this.fetch({
id: 'copy-bha-' + this.state.copySource + "-" + this.state.bhaId,
locally: function(){
if(this.hasAlreadyFetched('copy-bha-' + this.state.copySource + "-" + this.state.bhaId))
return this.state.candidates;
},
remotely: function(){
return Prime.BHAComponents.StateSource.copy(this.state.copySource, this.state.bhaId);
}
});
},
copyFailure: function(){
this.state.copyFailure = true;
},
openAddDialog: function(){
this.state.addDialogOpen= true;
this.hasChanged();
},
closeAddDialog: function(){
this.state.addDialogOpen= false;
this.hasChanged();
},
selectListedComponent: function(id, type){
this.state.addItem = {id: id, type: type, serialNumber: null};
this.hasChanged();
},
selectUnlistedComponent: function(serialNumber){
this.state.addItem = {
id: null,
type: null,
serialNumber: serialNumber
};
this.hasChanged();
},
fetchComponentDetails: function(id, type){
return this.fetch({
id: 'component-details-' + this.state.addItem.id + "-" + this.state.addItem.type,
locally: function(){
if(!this.state.addItem.id || this.hasAlreadyFetched('component-details-' + this.state.addItem.id + "-" + this.state.addItem.type))
return this.state.addItem;
},
remotely: function(){
return Prime.BHAComponents.StateSource.fetchComponentDetails(this.state.addItem.id, this.state.addItem.type);
}
});
},
receiveComponentDetails: function(details){
this.state.addItem = { id: details.id, type: details.type, serialNumber: details.serialNumber, vendor: details.vendor};
this.hasChanged();
}
});
@dangerbell
Copy link

Looks good overall. I'll have to take a closer look at Marty. The State Source idea seems interesting.

How's do you like React now that you've used it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment