2020-01-18 10:13:50 +01:00
|
|
|
import classic from 'ember-classic-decorator';
|
2018-12-29 01:27:37 +01:00
|
|
|
import { inject as service } from '@ember/service';
|
2020-01-18 10:13:50 +01:00
|
|
|
import { not, readOnly } from '@ember/object/computed';
|
2018-12-29 01:27:37 +01:00
|
|
|
import Controller, { inject as controller } from '@ember/controller';
|
|
|
|
import { getOwner } from '@ember/application';
|
|
|
|
import { isPresent, isEmpty } from '@ember/utils';
|
|
|
|
import EmberObject, { computed } from '@ember/object';
|
2015-11-12 15:52:14 +01:00
|
|
|
import {
|
|
|
|
validator, buildValidations
|
|
|
|
}
|
|
|
|
from 'ember-cp-validations';
|
2015-11-23 13:32:40 +01:00
|
|
|
import moment from 'moment';
|
2018-12-29 21:16:18 +01:00
|
|
|
import config from 'croodle/config/environment';
|
2015-11-12 15:52:14 +01:00
|
|
|
|
2016-01-28 23:48:14 +01:00
|
|
|
const validCollection = function(collection) {
|
2015-11-12 15:52:14 +01:00
|
|
|
// return false if any object in collection is inValid
|
|
|
|
return !collection.any((object) => {
|
|
|
|
return object.get('validations.isInvalid');
|
|
|
|
});
|
|
|
|
};
|
2016-01-28 23:48:14 +01:00
|
|
|
const Validations = buildValidations({
|
2016-06-21 01:13:09 +02:00
|
|
|
name: [
|
|
|
|
validator('presence', {
|
2018-12-28 22:26:34 +01:00
|
|
|
presence: true,
|
2018-12-29 01:27:37 +01:00
|
|
|
disabled: readOnly('model.anonymousUser'),
|
2020-01-30 00:23:12 +01:00
|
|
|
dependentKeys: ['model.intl.locale']
|
2016-06-21 01:13:09 +02:00
|
|
|
}),
|
|
|
|
validator('unique', {
|
2019-04-20 23:29:59 +02:00
|
|
|
parent: 'poll',
|
2016-06-21 01:13:09 +02:00
|
|
|
attributeInParent: 'users',
|
2020-01-30 00:23:12 +01:00
|
|
|
dependentKeys: ['model.poll.users.[]', 'model.poll.users.@each.name', 'model.intl.locale'],
|
2018-12-29 01:27:37 +01:00
|
|
|
disable: readOnly('model.anonymousUser'),
|
2020-01-30 00:23:12 +01:00
|
|
|
messageKey: 'errors.uniqueName',
|
2019-06-14 23:58:53 +02:00
|
|
|
ignoreNewRecords: true,
|
2016-06-21 01:13:09 +02:00
|
|
|
})
|
|
|
|
],
|
2015-11-12 15:52:14 +01:00
|
|
|
|
|
|
|
selections: [
|
|
|
|
validator('collection', true),
|
|
|
|
|
|
|
|
// all selection objects must be valid
|
|
|
|
// if forceAnswer is true in poll settings
|
|
|
|
validator(validCollection, {
|
2020-01-30 00:23:12 +01:00
|
|
|
dependentKeys: ['model.forceAnswer', 'model.selections.[]', 'model.selections.@each.value', 'model.intl.locale']
|
2015-11-12 15:52:14 +01:00
|
|
|
})
|
|
|
|
]
|
|
|
|
});
|
2015-11-02 23:02:59 +01:00
|
|
|
|
2016-01-28 23:48:14 +01:00
|
|
|
const SelectionValidations = buildValidations({
|
2015-11-12 15:52:14 +01:00
|
|
|
value: validator('presence', {
|
2018-12-28 22:26:34 +01:00
|
|
|
presence: true,
|
2018-12-29 01:27:37 +01:00
|
|
|
disabled: not('model.forceAnswer'),
|
2018-12-28 22:26:34 +01:00
|
|
|
messageKey: computed('model.isFreeText', function() {
|
2020-01-30 00:23:12 +01:00
|
|
|
return this.get('model.isFreeText') ? 'errors.present' : 'errors.answerRequired';
|
2018-12-28 22:26:34 +01:00
|
|
|
}),
|
2020-01-30 00:23:12 +01:00
|
|
|
dependentKeys: ['model.intl.locale']
|
2015-11-12 15:52:14 +01:00
|
|
|
})
|
|
|
|
});
|
2015-11-02 23:02:59 +01:00
|
|
|
|
2020-01-18 10:13:50 +01:00
|
|
|
@classic
|
|
|
|
class SelectionObject extends EmberObject.extend(SelectionValidations) {
|
2020-01-30 00:23:12 +01:00
|
|
|
@service intl;
|
|
|
|
|
2020-01-18 10:13:50 +01:00
|
|
|
value = null;
|
2020-01-30 00:23:12 +01:00
|
|
|
|
|
|
|
init() {
|
|
|
|
super.init(...arguments);
|
|
|
|
|
|
|
|
// current locale needs to be consumed in order to be observeable
|
|
|
|
// for localization of validation messages
|
|
|
|
this.intl.locale;
|
|
|
|
}
|
2020-01-18 10:13:50 +01:00
|
|
|
}
|
|
|
|
|
2016-08-02 01:55:48 +02:00
|
|
|
export default Controller.extend(Validations, {
|
2015-11-02 23:02:59 +01:00
|
|
|
actions: {
|
2019-06-12 09:07:48 +02:00
|
|
|
async submit() {
|
2019-04-20 23:29:59 +02:00
|
|
|
if (!this.get('validations.isValid')) {
|
|
|
|
return;
|
2015-11-12 15:52:14 +01:00
|
|
|
}
|
2019-04-20 23:29:59 +02:00
|
|
|
|
|
|
|
let poll = this.poll;
|
|
|
|
let selections = this.selections.map(({ value }) => {
|
|
|
|
if (value === null) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.isFreeText) {
|
|
|
|
return {
|
|
|
|
label: value,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// map selection to answer if it's not freetext
|
|
|
|
let answer = poll.answers.findBy('type', value);
|
|
|
|
let { icon, label, labelTranslation, type } = answer;
|
|
|
|
|
|
|
|
return {
|
|
|
|
icon,
|
|
|
|
label,
|
|
|
|
labelTranslation,
|
|
|
|
type,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
let user = this.store.createRecord('user', {
|
|
|
|
creationDate: new Date(),
|
|
|
|
name: this.name,
|
|
|
|
poll,
|
|
|
|
selections,
|
|
|
|
version: config.APP.version,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.set('newUserRecord', user);
|
2019-06-12 09:07:48 +02:00
|
|
|
await this.actions.save.bind(this)();
|
2016-08-04 22:24:53 +02:00
|
|
|
},
|
2019-04-20 23:29:59 +02:00
|
|
|
async save() {
|
|
|
|
let user = this.newUserRecord;
|
2016-08-04 22:24:53 +02:00
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
try {
|
|
|
|
await user.save();
|
2016-08-04 22:24:53 +02:00
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
this.set('savingFailed', false);
|
|
|
|
} catch (error) {
|
|
|
|
// couldn't save user model
|
2016-08-04 22:24:53 +02:00
|
|
|
this.set('savingFailed', true);
|
2019-04-20 23:29:59 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset form
|
|
|
|
this.set('name', '');
|
|
|
|
this.selections.forEach((selection) => {
|
|
|
|
selection.set('value', null);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.transitionToRoute('poll.evaluation', this.model, {
|
|
|
|
queryParams: { encryptionKey: this.encryption.key }
|
2016-08-04 22:24:53 +02:00
|
|
|
});
|
2015-11-02 23:02:59 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
anonymousUser: readOnly('poll.anonymousUser'),
|
2020-01-30 00:23:12 +01:00
|
|
|
currentLocale: readOnly('intl.locale'),
|
2018-12-29 01:27:37 +01:00
|
|
|
encryption: service(),
|
2019-04-20 23:29:59 +02:00
|
|
|
forceAnswer: readOnly('poll.forceAnswer'),
|
2020-01-30 00:23:12 +01:00
|
|
|
intl: service(),
|
2016-05-23 12:42:47 +02:00
|
|
|
|
|
|
|
init() {
|
2018-12-29 01:27:37 +01:00
|
|
|
this._super(...arguments);
|
|
|
|
|
2020-01-30 00:23:12 +01:00
|
|
|
// current locale needs to be consumed in order to be observeable
|
|
|
|
// for localization of validation messages
|
|
|
|
this.intl.locale;
|
2016-05-23 12:42:47 +02:00
|
|
|
},
|
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
isFreeText: readOnly('poll.isFreeText'),
|
|
|
|
isFindADate: readOnly('poll.isFindADate'),
|
2015-11-12 15:52:14 +01:00
|
|
|
|
2018-12-29 01:27:37 +01:00
|
|
|
momentLongDayFormat: readOnly('pollController.momentLongDayFormat'),
|
2017-08-11 16:39:36 +02:00
|
|
|
|
2015-11-12 15:52:14 +01:00
|
|
|
name: '',
|
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
options: readOnly('poll.options'),
|
2017-08-11 16:39:36 +02:00
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
poll: readOnly('model'),
|
2018-12-29 01:27:37 +01:00
|
|
|
pollController: controller('poll'),
|
2015-11-12 15:52:14 +01:00
|
|
|
|
2019-04-20 23:29:59 +02:00
|
|
|
possibleAnswers: computed('poll.answers', function() {
|
|
|
|
return this.get('poll.answers').map((answer) => {
|
2016-08-12 19:19:19 +02:00
|
|
|
const owner = getOwner(this);
|
2015-11-24 00:53:03 +01:00
|
|
|
|
2016-08-02 01:55:48 +02:00
|
|
|
const AnswerObject = EmberObject.extend({
|
2015-11-24 00:53:03 +01:00
|
|
|
icon: answer.get('icon'),
|
|
|
|
type: answer.get('type')
|
|
|
|
});
|
2015-11-02 23:02:59 +01:00
|
|
|
|
2016-08-02 01:55:48 +02:00
|
|
|
if (!isEmpty(answer.get('labelTranslation'))) {
|
2019-10-29 12:31:22 +01:00
|
|
|
return AnswerObject.extend({
|
2020-01-30 00:23:12 +01:00
|
|
|
intl: service(),
|
|
|
|
label: computed('intl.locale', function() {
|
|
|
|
return this.intl.t(this.labelTranslation);
|
2015-11-24 00:53:03 +01:00
|
|
|
}),
|
2020-01-30 00:23:12 +01:00
|
|
|
labelTranslation: answer.get('labelTranslation'),
|
2019-10-29 12:31:22 +01:00
|
|
|
}).create(owner.ownerInjection());
|
2015-11-12 15:52:14 +01:00
|
|
|
} else {
|
2015-11-24 00:53:03 +01:00
|
|
|
return AnswerObject.extend({
|
|
|
|
label: answer.get('label')
|
|
|
|
});
|
2015-11-02 23:02:59 +01:00
|
|
|
}
|
2015-11-12 15:52:14 +01:00
|
|
|
});
|
|
|
|
}),
|
2015-11-02 23:02:59 +01:00
|
|
|
|
2016-08-04 22:24:53 +02:00
|
|
|
savingFailed: false,
|
|
|
|
|
2017-08-11 16:39:36 +02:00
|
|
|
selections: computed('options', 'pollController.dates', function() {
|
2018-12-29 20:35:04 +01:00
|
|
|
let options = this.options;
|
|
|
|
let isFindADate = this.isFindADate;
|
2016-01-28 23:48:14 +01:00
|
|
|
let lastDate;
|
2015-11-12 15:52:14 +01:00
|
|
|
|
|
|
|
return options.map((option) => {
|
2016-01-28 23:48:14 +01:00
|
|
|
let labelValue;
|
2017-08-11 16:39:36 +02:00
|
|
|
let momentFormat;
|
|
|
|
let value = option.get('title');
|
2015-11-12 15:52:14 +01:00
|
|
|
|
|
|
|
// format label
|
|
|
|
if (isFindADate) {
|
2017-08-11 16:39:36 +02:00
|
|
|
let hasTime = value.length > 10; // 'YYYY-MM-DD'.length === 10
|
2018-12-29 20:35:04 +01:00
|
|
|
let timezone = this.timezone;
|
2017-08-11 16:39:36 +02:00
|
|
|
let date = isPresent(timezone) ? moment.tz(value, timezone) : moment(value);
|
|
|
|
if (hasTime && lastDate && date.format('YYYY-MM-DD') === lastDate.format('YYYY-MM-DD')) {
|
|
|
|
labelValue = value;
|
2015-11-12 15:52:14 +01:00
|
|
|
// do not repeat dates for different times
|
2017-08-11 16:39:36 +02:00
|
|
|
momentFormat = 'LT';
|
2015-11-12 15:52:14 +01:00
|
|
|
} else {
|
2017-08-11 16:39:36 +02:00
|
|
|
labelValue = value;
|
|
|
|
momentFormat = hasTime ? 'LLLL' : 'day';
|
|
|
|
lastDate = date;
|
2015-11-02 23:02:59 +01:00
|
|
|
}
|
2016-01-28 23:48:14 +01:00
|
|
|
} else {
|
2017-08-11 16:39:36 +02:00
|
|
|
labelValue = value;
|
2015-11-12 15:52:14 +01:00
|
|
|
}
|
|
|
|
|
2019-10-29 12:31:22 +01:00
|
|
|
// https://github.com/offirgolan/ember-cp-validations#basic-usage---objects
|
|
|
|
// To lookup validators, container access is required which can cause an issue with Object creation
|
|
|
|
// if the object is statically imported. The current fix for this is as follows.
|
|
|
|
let owner = getOwner(this);
|
|
|
|
return SelectionObject.create(owner.ownerInjection(), {
|
2016-01-28 23:48:14 +01:00
|
|
|
labelValue,
|
2020-01-18 10:13:50 +01:00
|
|
|
momentFormat,
|
|
|
|
|
|
|
|
// forceAnswer and isFreeText must be included in model
|
|
|
|
// cause otherwise validations can't depend on it
|
|
|
|
forceAnswer: this.forceAnswer,
|
|
|
|
isFreeText: this.isFreeText,
|
2017-08-11 16:39:36 +02:00
|
|
|
});
|
2015-11-12 15:52:14 +01:00
|
|
|
});
|
2017-08-11 16:39:36 +02:00
|
|
|
}),
|
|
|
|
|
2018-12-29 01:27:37 +01:00
|
|
|
timezone: readOnly('pollController.timezone')
|
2015-11-02 23:02:59 +01:00
|
|
|
});
|