Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions app/controllers/project/donate.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Ember from 'ember';
import FriendlyError from 'code-corps-ember/utils/friendly-error';
import { isValidationError } from 'code-corps-ember/utils/error-utils';

const {
Controller,
Expand All @@ -14,16 +15,6 @@ const CUSTOMER_CREATION_ERROR = 'There was a problem in connecting your account
const CARD_CREATION_ERROR = 'There was a problem in using your payment information. Please try again.';
const SUBSCRIPTION_CREATION_ERROR = 'There was a problem in setting up your monthly donation. Please try again.';

function isValidationError(payload) {
if (!payload.isAdapterError) {
return false;
}

let errors = payload.errors || [];

return errors.some((e) => e.id == 'VALIDATION_ERROR');
}

export default Controller.extend({
amount: null,
isAddingCard: false,
Expand Down
33 changes: 20 additions & 13 deletions app/controllers/project/settings/donations.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Ember from 'ember';
import FriendlyError from 'code-corps-ember/utils/friendly-error';
import { isValidationError } from 'code-corps-ember/utils/error-utils';

const {
Controller,
Expand All @@ -7,6 +9,8 @@ const {
set
} = Ember;

const PROBLEM_SAVING_DONATION_GOAL = 'There was a problem saving your donation goal. Please try again.';

export default Controller.extend({
projectDonationGoals: service(),
store: service(),
Expand All @@ -20,8 +24,8 @@ export default Controller.extend({
*/
activateDonations(project) {
get(this, 'store')
.createRecord('stripe-connect-plan', { project })
.save();
.createRecord('stripe-connect-plan', { project })
.save();
},

/**
Expand Down Expand Up @@ -74,7 +78,7 @@ export default Controller.extend({
/**
* Action which commits changes to a donation goal.
*
* Triggers when user clicks the save button while edditing or
* Triggers when user clicks the save button while editing or
* adding a new donation goal.
*
* @method saveDonationGoal
Expand All @@ -83,16 +87,19 @@ export default Controller.extend({
*/
saveDonationGoal(donationGoal, properties) {
donationGoal.setProperties(properties);
console.log('set');
donationGoal.save().then((donationGoal) => {
let projectDonationGoals = get(this, 'projectDonationGoals');
let project = get(this, 'project');
project.reload().then((project) => {
projectDonationGoals.reload(project).then(() => {
this.send('cancelDonationGoal', donationGoal);
});
});
});
donationGoal.save()
.then((donationGoal) => this._onDoneSaving(donationGoal))
.catch((response) => this._onFailedSaving(response));
}
},

_onDoneSaving(donationGoal) {
set(donationGoal, 'isEditing', false);
},

_onFailedSaving(response) {
if (!isValidationError(response)) {
set(this, 'error', new FriendlyError(PROBLEM_SAVING_DONATION_GOAL));
}
}
});
5 changes: 5 additions & 0 deletions app/styles/components/donation-goal-edit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@
border-width: 0 1px;
border-radius: 0;
}

}

.error {
clear: left;
}
}
7 changes: 7 additions & 0 deletions app/templates/components/donation-goal-edit.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
{{input class="amount" name="amount" type="number" placeholder="Custom amount" value=amount}}
<span class="period">per month</span>
</div>
{{#each donationGoal.errors.amount as |error|}}
<p class="error">{{error.message}}</p>
{{/each}}
<div class="input-group">
{{textarea
class="description"
name="description"
placeholder="Tell your donors what this goal will allow you to do. Be specific, but make it interesting!"
value=description}}
</div>
{{#each donationGoal.errors.description as |error|}}
<p class="error">{{error.message}}</p>
{{/each}}

<div class="input-group">
<button class="default save" {{action save (hash amount=amount description=description)}}>
{{#if donationGoal.isNew}}Create Goal{{else}}Save changes{{/if}}
Expand Down
3 changes: 3 additions & 0 deletions app/templates/project/settings/donations.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
</div>
{{/if}}
{{/if}}
{{#if error}}
{{error-formatter error=error}}
{{/if}}
</div>

<div class="settings-sidebar">
Expand Down
19 changes: 19 additions & 0 deletions app/utils/error-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Figures out if an error payload received from the server
* contains validation errors and thus is a validation error payload
*
* This is done by checking for presence of a `source` property in
* any of the received error objects.
*
* @param {DS.AdapterError} payload An instance of a `DS.AdapterError`
* @return {Boolean} `true` if the payload is a validaton error payload
*/
export function isValidationError(payload) {
if (!payload.isAdapterError) {
return false;
}

let errors = payload.errors || [];

return errors.some((e) => e.source);
}
79 changes: 79 additions & 0 deletions tests/acceptance/project-donation-goals-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { authenticateAsMemberOfRole } from 'code-corps-ember/tests/helpers/authe
import createOrganizationWithSluggedRoute from 'code-corps-ember/tests/helpers/mirage/create-organization-with-slugged-route';
import createProjectWithSluggedRoute from 'code-corps-ember/tests/helpers/mirage/create-project-with-slugged-route';
import projectSettingsDonationsPage from '../pages/project/settings/donations';
import Mirage from 'ember-cli-mirage';

moduleForAcceptance('Acceptance | Project Donation Goals');

Expand Down Expand Up @@ -249,3 +250,81 @@ test('it does not show donation progress if donations are not active', function(
assert.notOk(projectSettingsDonationsPage.donationProgress.isVisible, 'It does not show donation progress.');
});
});

test('it renders validation errors', function(assert) {
assert.expect(3);

let project = createProjectWithSluggedRoute();
let { organization } = project;
organization.createStripeConnectAccount();

authenticateAsMemberOfRole(this.application, server, organization, 'owner');

let done = assert.async();

server.post('donation-goals', function() {
done();
return new Mirage.Response(422, {}, {
errors: [{
id: 'VALIDATION_ERROR',
source: { pointer: 'data/attributes/amount' },
detail: 'Amount is required',
status: 422
}, {
id: 'VALIDATION_ERROR',
source: { pointer: 'data/attributes/description' },
detail: 'Description is required',
status: 422
}]
});
});

projectSettingsDonationsPage.visit({ organization: organization.slug, project: project.slug });

andThen(() => {
let form = projectSettingsDonationsPage.editedDonationGoals(0);
form.clickSave();
});

andThen(() => {
let form = projectSettingsDonationsPage.editedDonationGoals(0);

assert.equal(form.validationErrors().count, 2, 'Both validation errors are rendered.');
assert.equal(form.validationErrors(0).message, 'Amount is required');
assert.equal(form.validationErrors(1).message, 'Description is required');
});
});

test('it renders other errors', function(assert) {
assert.expect(1);

let project = createProjectWithSluggedRoute();
let { organization } = project;
organization.createStripeConnectAccount();

authenticateAsMemberOfRole(this.application, server, organization, 'owner');

let done = assert.async();

server.post('donation-goals', function() {
done();
return new Mirage.Response(500, {}, {
errors: [{
id: 'INTERNAL SERVER ERROR',
title: 'Something went wrong',
detail: 'Something went wrong',
status: 500
}]
});
});

projectSettingsDonationsPage.visit({ organization: organization.slug, project: project.slug });

andThen(() => {
projectSettingsDonationsPage.editedDonationGoals(0).clickSave();
});

andThen(() => {
assert.equal(projectSettingsDonationsPage.errorFormatter.errors().count, 1, 'The error is displayed');
});
});
12 changes: 11 additions & 1 deletion tests/pages/project/settings/donations.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import {
collection,
create,
fillable,
text,
visitable
} from 'ember-cli-page-object';
import donationProgress from 'code-corps-ember/tests/pages/components/donations/donation-progress';
import errorFormatter from 'code-corps-ember/tests/pages/components/error-formatter';

export default create({
visit: visitable(':organization/:project/settings/donations'),
Expand All @@ -26,10 +28,18 @@ export default create({
amount: fillable('input[name=amount]'),
description: fillable('textarea[name=description]'),
clickSave: clickable('.save'),
clickCancel: clickable('.cancel')
clickCancel: clickable('.cancel'),
validationErrors: collection({
itemScope: '.error',
item: {
message: text('')
}
})
}
}),

errorFormatter,

stripeConnectButton: {
scope: '.stripe-connect',
href: attribute('href')
Expand Down