Skip to content

Instantly share code, notes, and snippets.

@brownish
Created June 3, 2016 18:04
Show Gist options
  • Save brownish/db88066ce5a1145c17fa1e2a440bba10 to your computer and use it in GitHub Desktop.
Save brownish/db88066ce5a1145c17fa1e2a440bba10 to your computer and use it in GitHub Desktop.
mobx store
class State {
id = null;
@observable name;
@observable abbreviation;
@observable smithsonianCode;
@observable fipsCode;
@observable gnisCode;
@observable _counties = asMap([]);
@observable _cities = asMap([]);
@observable _sites = asMap([]);
@observable createdAt;
@observable updatedAt;
@observable saved = false;
@observable saving = false;
@observable deleting = false;
@observable deleted = false;
@observable selected = false;
store = null;
_deleteHandler
_saveHandler = null;
get counties() {
return this._counties.values();
}
@computed get asJson() {
return {
id: this.id,
name: this.name,
abbreviation: this.abbreviation,
smithsonianCode: this.smithsonianCode,
fipsCode: this.fipsCode,
gnisCode: this.gnisCode
};
}
@computed get tableFormat() {
return {
id: this.id,
name: this.name,
abbreviation: this.abbreviation,
smithsonianCode: this.smithsonianCode,
fipsCode: this.fipsCode,
gnisCode: this.gnisCode
};
}
@computed get dropdownFormat() {
return `${this.name}`;
}
@computed get detailsFormat() {
return {
id: this.id,
name: this.name,
abbreviation: this.abbreviation,
smithsonianCode: this.smithsonianCode,
fipsCode: this.fipsCode,
gnisCode: this.gnisCode
};
}
constructor(store, state) {
this.store = store;
const { id, name, abbreviation, smithsonianCode, fipsCode, gnisCode, createdAt, updatedAt, deleted=true } = state;
if (id) this.saved = true;
this.id = id || uuid.v4();
this.name = name;
this.abbreviation = abbreviation;
this.smithsonianCode = smithsonianCode;
this.fipsCode = fipsCode;
this.gnisCode = gnisCode;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.deleted = deleted;
this._deleteHandler = autorun(() => {
if (this.deleted) {
this.store.removeItem(this);
}
});
this._saveHandler = autorun(() => {
if (this.saving) {
this.store.saveItem(this);
}
});
// makes sure the state has _counties, throws error without this check
if (this._counties) {
intercept(this, "_counties", change => {
console.log('_counties changed!', change);
return change;
});
}
if (this.name) {
intercept(this, 'name', change => {
console.log('NAME CHANGED', change);
console.log(this.counties);
return change;
})
}
}
@action select() {
this.selected = true;
}
@action deselect() {
this.selected = false;
}
@action save() {
this.saving = true;
this.store.saveItem(this.asJson);
}
@action delete() {
this.deleting = true;
this._saveHandler();
this.store.deleteItem(this);
}
@action updateFromServer(update) {
console.log('UPDATED VERSION', update);
console.log('EXISTING VERSION', this.asJson);
console.log('EQUALITY TEST', update == this.asJson);
}
@action addCounty(county) {
county = this.store.stores.counties.findOrAddCounty(county);
this._counties.set(county.id, county);
}
}
export default class StateStore {
primus;
stores;
name = 'states';
urlParam = 'states';
label = 'States';
columns = [
{name: 'name'},
{name: 'abbreviation'},
{name: 'smithsonianCode'},
{name: 'fipsCode'},
{name: 'gnisCode'}
];
@observable items = asMap([]);
@observable pendingRequestCount = 0;
@observable initialDataLoaded = false;
@observable error = null;
@observable selected = false;
@observable selectedId = null;
@computed get tableItems() {
return this.items.values().slice().filter(i => i.saved == true).map(i => i.tableFormat);
}
@computed get dropdownItems() {
// return this.items.values().slice().map(i => i.dropdownFormat);
return this.items.values();
}
constructor(primus, stores, items) {
console.log('initializing StateStore!');
this.primus = primus;
this.stores = stores;
this.primus.on('graphql', (error, response) => {
if (error) {
this.error = error;
}
if (response.states) {
this.handleResponse(response.states);
}
if (response.state) {
this.handleResponse(response.state);
}
if (response.addState) {
this.handleResponse(response.addState);
}
if (response.updateState) {
this.handleResponse(response.updateState);
}
if (response.deleteState) {
this.handleResponse(response.deleteState);
}
});
if (typeof window !== 'undefined' && !this.items.length && !this.initialDataLoaded) {
this.getItems();
this.initialDataLoaded = true;
}
}
@action newItem() {
const selected = this.selectedItem;
if (selected) {
selected.deselect();
}
const newItem = new State(this, {});
console.log('NEW ITEM', newItem);
this.items.set(newItem.id, newItem);
this.selectItem(newItem.id);
}
@computed get isLoading() {
return this.pendingRequestCount > 0;
}
@action getItems() {
console.log('getting items');
const payload = {
query: `query {
states {
id,
name,
abbreviation,
smithsonianCode,
fipsCode,
gnisCode,
createdAt,
updatedAt
}}`
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action getItem(id) {
const payload = {
variables: {id},
query: `query ($id: ID!) {
state (id: $id) {
id,
name,
abbreviation,
smithsonianCode,
fipsCode,
gnisCode,
counties {id, name},
createdAt,
updatedAt
}}`
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action saveItem(item) {
console.log('SAVING ITEM', item);
const updateQuery = `mutation ($item: UpdatedState!) {
updateState (state: $item) {
id,
name,
abbreviation,
smithsonianCode,
fipsCode,
gnisCode,
createdAt,
updatedAt
}}`;
const newQuery = `mutation ($item: NewState!) {
addState (state: $item) {
id,
name,
abbreviation,
smithsonianCode,
fipsCode,
gnisCode,
createdAt,
updatedAt
}}`;
const payload = {
query: item.saved ? updateQuery : newQuery,
variables: {item: item.asJson}
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action deleteItem(item) {
const payload = {
query: `mutation ($id: ID!) {deleteState (id: $id){id,deleted}}`,
variables: {id: item.id}
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action removeItem(item) {
if (this.items.has(item.id)) {
this.items.delete(item.id);
}
}
@action select() {
this.selected = true;
}
@action deselect() {
this.selected = false;
}
@computed get selectedItem() {
if (this.items.has(this.selectedId)) {
return this.items.get(this.selectedId);
} else {
return null;
}
}
@action selectItem(id) {
this.selectedId = id;
}
@action handleResponse(response) {
if (!Array.isArray(response)) response = [response];
response.forEach(item => {
if (this.items.has(item.id)) {
this.items.get(item.id).updateFromServer(item);
} else {
this.items.set(item.id, new State(this, item));
}
});
this.pendingRequestCount--;
}
@action findOrAddState(state) {
if (!this.items.has(state.id)) {
this.items.set(state.id, new State(this, state));
}
return this.items.get(state.id);
}
@computed get form() {
return {
type: t.struct({
id: t.maybe(UUID),
name: t.String,
abbreviation: t.String,
smithsonianCode: t.Number,
fipsCode: t.maybe(t.Number),
gnisCode: t.maybe(t.Number),
counties: t.list(this.stores.counties.form.type)
}),
options: {
fields: {
id: {
type: 'hidden'
},
counties: {
item: this.stores.counties.form.options
}
}
}
};
}
}
class County {
id = null;
@observable name;
@observable abbreviation;
@observable fipsCode;
@observable gnisCode;
@observable state;
@observable _cities = asMap([]);
@observable _sites = asMap([]);
@observable createdAt;
@observable updatedAt;
@observable saved = true;
@observable saving = false;
@observable deleting = false;
@observable deleted = false;
@observable selected = false;
store = null;
_deleteHandler = null;
_saveHandler = null;
@computed get asJson() {
return {
id: this.id,
name: this.name,
abbreviation: this.abbreviation,
state: this.state ? this.state.id : null,
createdAt: this.createdAt,
updatedAt: this.updatedAt
};
}
@computed get tableFormat() {
return {
id: this.id,
name: this.name,
abbreviation: this.abbreviation,
state: this.state ? this.state.name : ''
};
}
@computed get dropdownFormat() {
return `${this.name} (${this.state.name})`;
}
@computed get detailsFormat() {
return {
id: this.id,
name: this.name,
state: this.state ? this.state.name : null,
abbreviation: this.abbreviation,
fipsCode: this.fipsCode,
gnisCode: this.gnisCode
};
}
constructor(store, county) {
this.store = store;
const { id, name, abbreviation, createdAt, updatedAt, state, deleted=false } = county;
if (!id) this.saved = false;
this.id = id || uuid.v4();
this.name = name;
this.abbreviation = abbreviation;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.deleted = deleted;
if (state) {
this.addState(state);
}
this._deleteHandler = autorun(() => {
if (this.deleted) {
this.store.removeItem(this);
}
});
autorun(() => {
if (this.state && this.state.saving) {
console.log('STATE WAS SAVED, SHOULD I SAVE???');
}
})
this._saveHandler = autorun(() => {
const json = this.asJson;
if (this.saving) {
this.store.saveItem(json);
}
});
if (this.state) {
intercept(this, "state", change => {
console.log('state changed!', change);
console.log('old state', this.state.name, change.newValue.name);
console.log('old state has this county', this.state._counties.has(this.id));
this.state._counties.delete(this.id);
return change;
});
}
if (this.name) {
intercept(this, 'name', change => {
console.log('COUNTY NAME CHANGE', this.name, change);
return change;
});
}
}
@action select() {
this.selected = true;
}
@action deselect() {
this.selected = false;
}
@action save() {
this.store.saveItem(this.asJson);
}
@action delete() {
this.deleting = true;
this._saveHandler();
this.store.deleteItem(this);
}
@action addState(state) {
this.state = this.store.stores.states.findOrAddState(state);
if (this.saved && !this.state._counties.has(this.id)) {
this.state._counties.set(this.id, this);
}
}
@action addSite(site) {
if (!this._sites.has(site.id)) {
site = this.store.stores.sites.findOrAddSite(site);
this._sites.set(site.id, site);
}
}
@action addCity(city) {
if (!this._cities.has(city.id)) {
city = this.store.stores.cities.findOrAddCity(city);
this._cities.set(city.id, city);
}
}
}
export default class CountyStore {
primus;
stores;
name = 'counties';
urlParam = 'counties';
label = 'Counties';
columns = [
{name: 'name'},
{name: 'abbreviation'},
{name: 'state'}
];
@observable items = asMap([]);
@observable pendingRequestCount = 0;
@observable initialDataLoaded = false;
@observable error = null;
@observable selected = false;
@observable selectedId = null;
@computed get tableItems() {
return this.items.values()
.filter(i => i.saved)
.slice()
.map(i => i.tableFormat);
}
@computed get dropdownItems() {
return this.items.values().slice().map(i => i.dropdownFormat);
}
constructor(primus, stores, items) {
this.primus = primus;
this.stores = stores;
this.primus.on('graphql', (error, response) => {
if (error) {
this.error = error;
}
if (response.counties) {
this.handleResponse(response.counties);
}
if (response.county) {
this.handleResponse(response.county);
}
if (response.addCounty) {
this.handleResponse(response.addCounty);
}
if (response.updateCounty) {
this.handleResponse(response.updateCounty);
}
if (response.deleteCounty) {
this.handleResponse(response.deleteCounty);
}
});
if (typeof window !== 'undefined' && !this.items.length && !this.initialDataLoaded) {
this.getItems();
this.initialDataLoaded = true;
}
}
@action newItem() {
const selected = this.selectedItem;
if (selected) {
selected.deselect();
}
const newItem = new County(this, {});
console.log('NEW ITEM', newItem);
this.items.set(newItem.id, newItem);
this.selectItem(newItem.id);
}
@computed get isLoading() {
return this.pendingRequestCount > 0;
}
@action getItems() {
const payload = {
query: `query {
counties {
id,
name,
abbreviation,
state {id, name},
createdAt,
updatedAt
}}`
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action getItem(id) {
const payload = {
variables: {id},
query: `query ($id: ID!) {
county (id: $id) {
id,
name,
abbreviation,
fipsCode,
gnisCode,
state {id, name},
createdAt,
updatedAt
}}`
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
saveItem(item) {
const updateQuery = `mutation ($item: updatedCounty!) {
updateCounty (county: $item) {
id,
name,
state {id, name},
createdAt,
updatedAt
}}`;
const newQuery = `mutation ($item: NewCounty!) {
addCounty (county: $item) {
id,
name,
state {id, name},
createdAt
}}`
const payload = {
query: this.saved ? updateQuery: newQuery,
variables: {item}
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action deleteItem(item) {
const payload = {
query: `mutation ($id: ID!) {deleteCounty (id: $id){id, deleted}}`,
variables: {id: item.id}
};
this.primus.emit('graphql', prepareGraphQLParams(payload));
this.pendingRequestCount++;
}
@action removeItem(item) {
if (this.items.has(item.id)) {
this.items.delete(item.id);
}
}
@action select() {
this.selected = true;
}
@action deselect() {
this.selected = false;
}
@computed get selectedItem() {
if (this.items.has(this.selectedId)) {
return this.items.get(this.selectedId);
} else {
return null;
}
}
@action selectItem(id) {
this.selectedId = id;
}
@action handleResponse(response) {
if (!Array.isArray(response)) response = [response];
response.forEach(item => {
this.items.set(item.id, new County(this, item));
});
this.pendingRequestCount--;
}
@action findOrAddCounty(county) {
if (!this.items.has(county.id)) {
this.items.set(county.id, new County(this, county));
}
return this.items.get(county.id);
}
@computed get form() {
const { states } = this.stores;
return {
type: t.struct({
id: t.maybe(UUID),
name: t.maybe(t.String),
abbreviation: t.maybe(t.String),
gnisCode: t.maybe(t.Number),
fipsCode: t.maybe(t.Number),
state: UUID
}),
options: {
fields: {
id: {
type: 'hidden'
},
state: {
factory: DropdownComponent(states.dropdownItems, states.pendingRequestCount > 0)
}
}
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment