Files

289 lines
8.3 KiB
JavaScript

import Ember from 'ember';
import DS from 'ember-data';
import moment from 'moment';
import TrackablesFromType from 'flaredown/mixins/trackables-from-type';
const {
get,
set,
computed,
computed: { alias },
inject: { service },
Component,
isNone,
run: { next },
RSVP: { all }
} = Ember;
export default Component.extend(TrackablesFromType, {
classNames: ['trackables-step'],
model: alias('parentView.model'),
tracking: service(),
setupTracking() {
this.get('tracking').setup({
at: new Date(this.get('checkin.date')),
trackableType: this.get('trackableType').capitalize()
});
},
checkin: alias('model.checkin'),
isTodaysCheckin: computed('checkin', function() {
return moment(this.get('checkin.date')).isSame(new Date(), 'day');
}),
sortedTrackeds: computed('trackeds.{[],@each.position}', function() {
return this.get('trackeds').toArray().sortBy('position');
}),
didReceiveAttrs() {
this._super(...arguments);
this.setupTracking();
},
removedTracked: null,
addedTracked: null,
actions: {
remove(tracked) {
tracked.prepareForDestroy();
this.set('removedTracked', tracked);
this.saveCheckin();
},
add(selectedTrackable) {
const trackeds = get(this, 'trackeds');
if (get(trackeds, 'isFulfilled')) {
this.addTrackable(get(trackeds, 'content'), selectedTrackable);
} else {
this.addTrackable(trackeds, selectedTrackable);
}
},
move(draggedId, droppedId) {
// Return if the item has been dropped onto its own dropzone
if (Ember.isEqual(draggedId, droppedId)) { return; }
let sortedTrackeds = this.get('sortedTrackeds');
let draggedItem = sortedTrackeds.findBy('id', draggedId);
// draggedItem might not be found if it's dragged from a different
// trackables' collection (this might happen in summary screen)
if (Ember.isNone(draggedItem)) { return; }
let draggedPosition = draggedItem.get('position');
let droppedPosition = 0;
if (Ember.isEqual(droppedId, 'after-last')) {
droppedPosition = sortedTrackeds.get('length');
} else {
let droppedItem = sortedTrackeds.findBy('id', droppedId);
droppedPosition = droppedItem.get('position');
}
// Return if the item has been dropped onto its next item's dropzone
if (Ember.isEqual(droppedPosition, draggedPosition + 1)) { return; }
if (draggedPosition > droppedPosition) {
// Case 1: Item Moved Up
// Shift down items between droppedPosition and draggedPosition
for (let i = droppedPosition; i < draggedPosition; i++) {
sortedTrackeds[i].set('position', i + 1);
}
draggedItem.set('position', droppedPosition);
} else {
// Case 2: Move Down
// Shift up items between draggedPosition and droppedPosition
for (let i = draggedPosition + 1; i < droppedPosition; i++) {
sortedTrackeds[i].set('position', i - 1);
}
draggedItem.set('position', droppedPosition - 1);
}
this.set('clickedTrackableId', null);
this.saveCheckin();
},
onTrackableClicked(trackableId) {
if (Ember.isPresent(this.get('clickedTrackableId'))) {
if (Ember.isEqual(trackableId, this.get('clickedTrackableId'))) {
this.set('clickedTrackableId', null);
} else {
this.set('clickedTrackableId', trackableId);
}
} else {
this.set('clickedTrackableId', trackableId);
}
},
saveChanges() {
this.saveCheckin();
},
completeStep() {
this.get('onStepCompleted')();
},
goBack() {
this.get('onGoBack')();
}
},
addTrackable(trackeds, trackable) {
const trackableType = get(this, 'trackableType');
const foundTrackable = trackeds.findBy(`${trackableType}.id`, trackable.get('id'));
if (isNone(foundTrackable)) {
const recordAttrs = {
colorId: this.computeNewColorId(),
position: trackeds.get('length'),
[trackableType]: trackable
};
const recordType = `checkin_${trackableType}`.camelize();
const tracked = this.store.createRecord(recordType, recordAttrs);
trackeds.pushObject(tracked);
set(this, 'addedTracked', tracked);
this.saveCheckin();
}
set(this, 'selectedTrackable', null);
},
computeNewColorId() {
var nColors = 32;
let usedColorIds = this.get('checkin.allColorIds');
// if all colors have been used
if (usedColorIds.length >= nColors) {
// re-use them again in the same order
return usedColorIds[(usedColorIds.length % nColors)];
} else {
// return a random unused color
let randomColor = '';
do {
randomColor = Math.floor(Math.random()*nColors)+'';
} while (usedColorIds.includes(randomColor));
return randomColor;
}
},
saveCheckin() {
set(this, 'checkin.hasDirtyAttributes', true);
next(this, () => {
set(this, 'isSaving', true);
all([
this.untrackRemovedTracked(),
this.trackAddedTracked()
])
.then(() => this.get('checkin').save())
.then(
() => {
Ember.Logger.info('Checkin successfully saved');
return this.onCheckinSaved();
},
(error) => {
this.get('checkin').handleSaveError(error);
}
)
.then(() => this.get('chartsVisibilityService').refresh())
.finally(() => {
set(this, 'isSaving', false);
});
});
},
onCheckinSaved() {
const checkin = this.get('checkin');
this.deleteAddedTracked();
checkin.set('hasDirtyAttributes', false);
checkin.deleteTrackablesPreparedForDestroy();
this.set('addedTracked', null);
this.set('removedTracked', null);
},
untrackRemovedTracked() {
// untrack() removedTracked if isTodaysCheckin
return new Ember.RSVP.Promise(resolve => {
let removedTracked = this.get('removedTracked');
if (this.get('isTodaysCheckin') && Ember.isPresent(removedTracked)) {
let rawTrackable = removedTracked.get(this.get('trackableType'));
if (DS.PromiseObject.detectInstance(rawTrackable)) {
let trackablePromise = rawTrackable;
if (trackablePromise.get('isFulfilled')) {
this.untrack(trackablePromise.get('content'), resolve);
} else {
trackablePromise.then(trackable => {
this.untrack(trackable, resolve);
});
}
} else {
Ember.Logger.debug('rawTrackable is not a DS.PromiseObject');
if (Ember.isPresent(rawTrackable)) {
this.untrack(rawTrackable, resolve);
}
}
} else {
resolve();
}
});
},
untrack(trackable, resolve) {
this.get('tracking').untrack(
{
trackable: trackable,
trackableType: this.get('trackableType').capitalize()
},
resolve
);
},
trackAddedTracked() {
// track() addedTracked if isTodaysCheckin
return new Ember.RSVP.Promise(resolve => {
var addedTracked = this.get('addedTracked');
if (this.get('isTodaysCheckin') && Ember.isPresent(addedTracked)) {
let rawTrackable = addedTracked.get(this.get('trackableType'));
if (DS.PromiseObject.detectInstance(rawTrackable)) {
let trackablePromise = rawTrackable;
if (trackablePromise.get('isFulfilled')) {
this.get('tracking').track(
trackablePromise.get('content'),
addedTracked.get('colorId'),
resolve
);
} else {
trackablePromise.then(trackable => {
this.get('tracking').track(
trackable,
addedTracked.get('colorId'),
resolve
);
});
}
} else {
Ember.Logger.debug('rawTrackable is not a DS.PromiseObject');
if (Ember.isPresent(rawTrackable)) {
this.get('tracking').track(
rawTrackable,
addedTracked.get('colorId'),
resolve
);
}
}
} else {
resolve();
}
});
},
deleteAddedTracked() {
// remove addedTracked to avoid 'ghost' record
let addedTracked = this.get('addedTracked');
if (Ember.isPresent(addedTracked)) {
addedTracked.deleteRecord();
}
}
});