Update number of contacts on contact page when adding/removing contacts

This commit is contained in:
Steffen van Bergerem 2015-07-24 02:32:04 +02:00
parent 5a5d595339
commit 4a178e20e5
6 changed files with 286 additions and 35 deletions

View file

@ -20,6 +20,8 @@ app.pages.Contacts = Backbone.View.extend({
$("#people_stream.contacts .header i").tooltip({"placement": "bottom"}); $("#people_stream.contacts .header i").tooltip({"placement": "bottom"});
$(document).on("ajax:success", "form.edit_aspect", this.updateAspectName); $(document).on("ajax:success", "form.edit_aspect", this.updateAspectName);
app.events.on("aspect:create", function(){ window.location.reload() }); app.events.on("aspect:create", function(){ window.location.reload() });
app.events.on("aspect_membership:create", this.addAspectMembership, this);
app.events.on("aspect_membership:destroy", this.removeAspectMembership, this);
this.aspectCreateView = new app.views.AspectCreate({ el: $("#newAspectContainer") }); this.aspectCreateView = new app.views.AspectCreate({ el: $("#newAspectContainer") });
this.aspectCreateView.render(); this.aspectCreateView.render();
@ -95,6 +97,26 @@ app.pages.Contacts = Backbone.View.extend({
revert: true, revert: true,
helper: "clone" helper: "clone"
}); });
},
updateAspectMembershipCount: function(id, change) {
var count = parseInt($("#aspect_nav [data-aspect-id='" + id + "'] .badge").text(), 10);
$("#aspect_nav [data-aspect-id='" + id + "'] .badge").text(count + change);
},
updateContactCount: function(change) {
var count = parseInt($("#aspect_nav .all_aspects .badge").text(), 10);
$("#aspect_nav .all_aspects .badge").text(count + change);
},
addAspectMembership: function(data) {
if(data.startSharing) { this.updateContactCount(1); }
this.updateAspectMembershipCount(data.membership.aspectId, 1);
},
removeAspectMembership: function(data) {
if(data.stopSharing) { this.updateContactCount(-1); }
this.updateAspectMembershipCount(data.membership.aspectId, -1);
} }
}); });
// @license-end // @license-end

View file

@ -77,20 +77,28 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
return aspect_membership.save(); return aspect_membership.save();
}, },
_successSaveCb: function(aspect_membership) { _successSaveCb: function(aspectMembership) {
var aspect_id = aspect_membership.get('aspect_id'); var aspectId = aspectMembership.get("aspect_id"),
var membership_id = aspect_membership.get('id'); membershipId = aspectMembership.get("id"),
var li = this.dropdown.find('li[data-aspect_id="'+aspect_id+'"]'); li = this.dropdown.find("li[data-aspect_id='" + aspectId + "']"),
personId = li.closest("ul.dropdown-menu").data("person_id"),
startSharing = false;
// the user didn't have this person in any aspects before, congratulate them // the user didn't have this person in any aspects before, congratulate them
// on their newly found friendship ;) // on their newly found friendship ;)
if( this.dropdown.find('li.selected').length === 0 ) { if( this.dropdown.find("li.selected").length === 0 ) {
var msg = Diaspora.I18n.t('aspect_dropdown.started_sharing_with', { 'name': this._name() }); var msg = Diaspora.I18n.t("aspect_dropdown.started_sharing_with", { "name": this._name() });
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg }); startSharing = true;
Diaspora.page.flashMessages.render({ "success": true, "notice": msg });
} }
li.attr('data-membership_id', membership_id) // just to be sure... app.events.trigger("aspect_membership:create", {
.data('membership_id', membership_id); membership: { aspectId: aspectId, personId: personId },
startSharing: startSharing
});
li.attr("data-membership_id", membershipId) // just to be sure...
.data("membership_id", membershipId);
this.updateSummary(li); this.updateSummary(li);
this._done(); this._done();
@ -119,21 +127,30 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
return aspect_membership.destroy(); return aspect_membership.destroy();
}, },
_successDestroyCb: function(aspect_membership) { _successDestroyCb: function(aspectMembership) {
var membership_id = aspect_membership.get('id'); var membershipId = aspectMembership.get("id"),
var li = this.dropdown.find('li[data-membership_id="'+membership_id+'"]'); li = this.dropdown.find("li[data-membership_id='" + membershipId + "']"),
aspectId = li.data("aspect_id"),
personId = li.closest("ul.dropdown-menu").data("person_id"),
stopSharing = false;
li.removeAttr('data-membership_id') li.removeAttr("data-membership_id")
.removeData('membership_id'); .removeData("membership_id");
this.updateSummary(li); this.updateSummary(li);
// we just removed the last aspect, inform the user with a flash message // we just removed the last aspect, inform the user with a flash message
// that he is no longer sharing with that person // that he is no longer sharing with that person
if( this.dropdown.find('li.selected').length === 0 ) { if( this.dropdown.find("li.selected").length === 0 ) {
var msg = Diaspora.I18n.t('aspect_dropdown.stopped_sharing_with', { 'name': this._name() }); var msg = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", { "name": this._name() });
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg }); stopSharing = true;
Diaspora.page.flashMessages.render({ "success": true, "notice": msg });
} }
app.events.trigger("aspect_membership:destroy", {
membership: { aspectId: aspectId, personId: personId },
stopSharing: stopSharing
});
this._done(); this._done();
}, },

View file

@ -36,31 +36,49 @@ app.views.Contact = app.views.Base.extend({
addContactToAspect: function(){ addContactToAspect: function(){
var self = this; var self = this;
// do we create the first aspect membership for this person?
var startSharing = this.model.get("aspect_memberships").length === 0;
this.model.aspect_memberships.create({ this.model.aspect_memberships.create({
'person_id': this.model.get('person_id'), "person_id": this.model.get("person_id"),
'aspect_id': app.aspect.get('id') "aspect_id": app.aspect.get("id")
},{ },{
success: function(){ success: function(){
app.events.trigger("aspect_membership:create", {
membership: {
aspectId: app.aspect.get("id"),
personId: self.model.get("person_id")
},
startSharing: startSharing
});
self.render(); self.render();
}, },
error: function(){ error: function(){
var msg = Diaspora.I18n.t('contacts.error_add', { 'name': self.model.get('person').name }); var msg = Diaspora.I18n.t("contacts.error_add", { "name": self.model.get("person").name });
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg }); Diaspora.page.flashMessages.render({ "success": false, "notice": msg });
} }
}); });
}, },
removeContactFromAspect: function(){ removeContactFromAspect: function(){
var self = this; var self = this;
// do we destroy the last aspect membership for this person?
var stopSharing = this.model.get("aspect_memberships").length <= 1;
this.model.aspect_memberships this.model.aspect_memberships
.find(function(membership){ return membership.get('aspect').id === app.aspect.id; }) .find(function(membership){ return membership.get("aspect").id === app.aspect.id; })
.destroy({ .destroy({
success: function(){ success: function(){
app.events.trigger("aspect_membership:destroy", {
membership: {
aspectId: app.aspect.get("id"),
personId: self.model.get("person_id")
},
stopSharing: stopSharing
});
self.render(); self.render();
}, },
error: function(){ error: function(){
var msg = Diaspora.I18n.t('contacts.error_remove', { 'name': self.model.get('person').name }); var msg = Diaspora.I18n.t("contacts.error_remove", { "name": self.model.get("person").name });
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg }); Diaspora.page.flashMessages.render({ "success": false, "notice": msg });
} }
}); });
} }

View file

@ -98,4 +98,150 @@ describe("app.pages.Contacts", function(){
expect(this.view.stream.search).toHaveBeenCalledWith("Username"); expect(this.view.stream.search).toHaveBeenCalledWith("Username");
}); });
}); });
describe("updateAspectMembershipCount", function() {
it("increases the badge count of an aspect", function() {
var aspect = $("#aspect_nav .aspect").eq(0);
$(".badge", aspect).text("15");
this.view.updateAspectMembershipCount(aspect.data("aspect-id"), 27);
expect($(".badge", aspect).text()).toBe("42");
});
it("decreases the badge count of an aspect", function() {
var aspect = $("#aspect_nav .aspect").eq(1);
$(".badge", aspect).text("42");
this.view.updateAspectMembershipCount(aspect.data("aspect-id"), -15);
expect($(".badge", aspect).text()).toBe("27");
});
});
describe("updateContactCount", function() {
it("increases the badge count of 'my aspects'", function() {
$("#aspect_nav .all_aspects .badge").text("15");
this.view.updateContactCount(27);
expect($("#aspect_nav .all_aspects .badge").text()).toBe("42");
});
it("decreases the badge count of 'my aspects'", function() {
$("#aspect_nav .all_aspects .badge").text("42");
this.view.updateContactCount(-15);
expect($("#aspect_nav .all_aspects .badge").text()).toBe("27");
});
});
describe("addAspectMembership", function() {
context("when the user starts sharing", function() {
beforeEach(function() {
this.data = {
membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") },
startSharing: true
};
});
it("is called on aspect_membership:create", function() {
spyOn(app.pages.Contacts.prototype, "addAspectMembership");
this.view = new app.pages.Contacts({stream: {render: function(){}}});
app.events.trigger("aspect_membership:create", this.data);
expect(app.pages.Contacts.prototype.addAspectMembership).toHaveBeenCalledWith(this.data);
});
it("calls updateContactCount", function() {
spyOn(this.view, "updateContactCount");
this.view.addAspectMembership(this.data);
expect(this.view.updateContactCount).toHaveBeenCalledWith(1);
});
it("calls updateAspectMembershipCount", function() {
spyOn(this.view, "updateAspectMembershipCount");
this.view.addAspectMembership(this.data);
expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, 1);
});
});
context("when the user doesn't start sharing", function() {
beforeEach(function() {
this.data = {
membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") },
startSharing: false
};
});
it("is called on aspect_membership:create", function() {
spyOn(app.pages.Contacts.prototype, "addAspectMembership");
this.view = new app.pages.Contacts({stream: {render: function(){}}});
app.events.trigger("aspect_membership:create", this.data);
expect(app.pages.Contacts.prototype.addAspectMembership).toHaveBeenCalledWith(this.data);
});
it("doesn't call updateContactCount", function() {
spyOn(this.view, "updateContactCount");
this.view.addAspectMembership(this.data);
expect(this.view.updateContactCount).not.toHaveBeenCalled();
});
it("calls updateAspectMembershipCount", function() {
spyOn(this.view, "updateAspectMembershipCount");
this.view.addAspectMembership(this.data);
expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, 1);
});
});
});
describe("removeAspectMembership", function() {
context("when the user stops sharing", function() {
beforeEach(function() {
this.data = {
membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") },
stopSharing: true
};
});
it("is called on aspect_membership:destroy", function() {
spyOn(app.pages.Contacts.prototype, "removeAspectMembership");
this.view = new app.pages.Contacts({stream: {render: function(){}}});
app.events.trigger("aspect_membership:destroy", this.data);
expect(app.pages.Contacts.prototype.removeAspectMembership).toHaveBeenCalledWith(this.data);
});
it("calls updateContactCount", function() {
spyOn(this.view, "updateContactCount");
this.view.removeAspectMembership(this.data);
expect(this.view.updateContactCount).toHaveBeenCalledWith(-1);
});
it("calls updateAspectMembershipCount", function() {
spyOn(this.view, "updateAspectMembershipCount");
this.view.removeAspectMembership(this.data);
expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, -1);
});
});
context("when the user doesn't stop sharing", function() {
beforeEach(function() {
this.data = {
membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") },
stopSharing: false
};
});
it("is called on aspect_membership:destroy", function() {
spyOn(app.pages.Contacts.prototype, "removeAspectMembership");
this.view = new app.pages.Contacts({stream: {render: function(){}}});
app.events.trigger("aspect_membership:destroy", this.data);
expect(app.pages.Contacts.prototype.removeAspectMembership).toHaveBeenCalledWith(this.data);
});
it("doesn't call updateContactCount", function() {
spyOn(this.view, "updateContactCount");
this.view.removeAspectMembership(this.data);
expect(this.view.updateContactCount).not.toHaveBeenCalled();
});
it("calls updateAspectMembershipCount", function() {
spyOn(this.view, "updateAspectMembershipCount");
this.view.removeAspectMembership(this.data);
expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, -1);
});
});
});
}); });

View file

@ -1,13 +1,13 @@
describe("app.views.AspectMembership", function(){ describe("app.views.AspectMembership", function(){
var resp_success = {status: 200, responseText: '{}'}; var success = {status: 200, responseText: "{}"};
var resp_fail = {status: 400}; var resp_fail = {status: 400};
beforeEach(function() { beforeEach(function() {
// mock a dummy aspect dropdown // mock a dummy aspect dropdown
spec.loadFixture("aspect_membership_dropdown"); spec.loadFixture("aspect_membership_dropdown");
this.view = new app.views.AspectMembership({el: $('.aspect_membership_dropdown')}); this.view = new app.views.AspectMembership({el: $('.aspect_membership_dropdown')});
this.person_id = $('.dropdown-menu').data('person_id'); this.personId = $(".dropdown-menu").data("person_id");
this.person_name = $('.dropdown-menu').data('person-short-name'); this.personName = $(".dropdown-menu").data("person-short-name");
Diaspora.I18n.load({ Diaspora.I18n.load({
aspect_dropdown: { aspect_dropdown: {
started_sharing_with: 'you started sharing with <%= name %>', started_sharing_with: 'you started sharing with <%= name %>',
@ -26,7 +26,7 @@ describe("app.views.AspectMembership", function(){
it('marks the aspect as selected', function() { it('marks the aspect as selected', function() {
this.newAspect.trigger('click'); this.newAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_success); jasmine.Ajax.requests.mostRecent().respondWith(success);
expect(this.newAspect.attr('class')).toContain('selected'); expect(this.newAspect.attr('class')).toContain('selected');
}); });
@ -34,19 +34,30 @@ describe("app.views.AspectMembership", function(){
it('displays flash message when added to first aspect', function() { it('displays flash message when added to first aspect', function() {
spec.content().find('li').removeClass('selected'); spec.content().find('li').removeClass('selected');
this.newAspect.trigger('click'); this.newAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_success); jasmine.Ajax.requests.mostRecent().respondWith(success);
expect($('[id^="flash"]')).toBeSuccessFlashMessage( expect($('[id^="flash"]')).toBeSuccessFlashMessage(
Diaspora.I18n.t('aspect_dropdown.started_sharing_with', {name: this.person_name}) Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: this.personName})
); );
}); });
it("triggers aspect_membership:create", function() {
spyOn(app.events, "trigger");
spec.content().find("li").removeClass("selected");
this.newAspect.trigger("click");
jasmine.Ajax.requests.mostRecent().respondWith(success);
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:create", {
membership: {aspectId: this.newAspectId, personId: this.personId},
startSharing: true
});
});
it('displays an error when it fails', function() { it('displays an error when it fails', function() {
this.newAspect.trigger('click'); this.newAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_fail); jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
expect($('[id^="flash"]')).toBeErrorFlashMessage( expect($('[id^="flash"]')).toBeErrorFlashMessage(
Diaspora.I18n.t('aspect_dropdown.error', {name: this.person_name}) Diaspora.I18n.t("aspect_dropdown.error", {name: this.personName})
); );
}); });
}); });
@ -59,7 +70,7 @@ describe("app.views.AspectMembership", function(){
it('marks the aspect as unselected', function(){ it('marks the aspect as unselected', function(){
this.oldAspect.trigger('click'); this.oldAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_success); jasmine.Ajax.requests.mostRecent().respondWith(success);
expect(this.oldAspect.attr('class')).not.toContain('selected'); expect(this.oldAspect.attr('class')).not.toContain('selected');
}); });
@ -67,19 +78,30 @@ describe("app.views.AspectMembership", function(){
it('displays a flash message when removed from last aspect', function() { it('displays a flash message when removed from last aspect', function() {
spec.content().find('li.selected:last').removeClass('selected'); spec.content().find('li.selected:last').removeClass('selected');
this.oldAspect.trigger('click'); this.oldAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_success); jasmine.Ajax.requests.mostRecent().respondWith(success);
expect($('[id^="flash"]')).toBeSuccessFlashMessage( expect($('[id^="flash"]')).toBeSuccessFlashMessage(
Diaspora.I18n.t('aspect_dropdown.stopped_sharing_with', {name: this.person_name}) Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: this.personName})
); );
}); });
it("triggers aspect_membership:destroy", function() {
spyOn(app.events, "trigger");
spec.content().find("li.selected:last").removeClass("selected");
this.oldAspect.trigger("click");
jasmine.Ajax.requests.mostRecent().respondWith(success);
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:destroy", {
membership: {aspectId: this.oldAspect.data("aspect_id"), personId: this.personId},
stopSharing: true
});
});
it('displays an error when it fails', function() { it('displays an error when it fails', function() {
this.oldAspect.trigger('click'); this.oldAspect.trigger('click');
jasmine.Ajax.requests.mostRecent().respondWith(resp_fail); jasmine.Ajax.requests.mostRecent().respondWith(resp_fail);
expect($('[id^="flash"]')).toBeErrorFlashMessage( expect($('[id^="flash"]')).toBeErrorFlashMessage(
Diaspora.I18n.t('aspect_dropdown.error_remove', {name: this.person_name}) Diaspora.I18n.t("aspect_dropdown.error_remove", {name: this.personName})
); );
}); });
}); });

View file

@ -57,6 +57,19 @@ describe("app.views.Contact", function(){
expect(this.model.aspect_memberships.length).toBe(2); expect(this.model.aspect_memberships.length).toBe(2);
}); });
it("triggers aspect_membership:create", function() {
spyOn(app.events, "trigger");
$(".contact_add-to-aspect", this.contact).trigger("click");
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200, // success
responseText: this.response
});
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:create", {
membership: {aspectId: app.aspect.get("id"), personId: this.model.get("person_id")},
startSharing: false
});
});
it('calls render', function() { it('calls render', function() {
spyOn(this.view, 'render'); spyOn(this.view, 'render');
$('.contact_add-to-aspect',this.contact).trigger('click'); $('.contact_add-to-aspect',this.contact).trigger('click');
@ -109,6 +122,19 @@ describe("app.views.Contact", function(){
expect(this.model.aspect_memberships.length).toBe(0); expect(this.model.aspect_memberships.length).toBe(0);
}); });
it("triggers aspect_membership:destroy", function() {
spyOn(app.events, "trigger");
$(".contact_remove-from-aspect", this.contact).trigger("click");
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200, // success
responseText: this.response
});
expect(app.events.trigger).toHaveBeenCalledWith("aspect_membership:destroy", {
membership: {aspectId: app.aspect.get("id"), personId: this.model.get("person_id")},
stopSharing: true
});
});
it('calls render', function() { it('calls render', function() {
spyOn(this.view, 'render'); spyOn(this.view, 'render');
$('.contact_remove-from-aspect',this.contact).trigger('click'); $('.contact_remove-from-aspect',this.contact).trigger('click');