diff --git a/app/assets/javascripts/app/models/contact.js b/app/assets/javascripts/app/models/contact.js index 5457f2c4e..22f26804b 100644 --- a/app/assets/javascripts/app/models/contact.js +++ b/app/assets/javascripts/app/models/contact.js @@ -2,12 +2,12 @@ app.models.Contact = Backbone.Model.extend({ initialize : function() { - this.aspect_memberships = new app.collections.AspectMemberships(this.get('aspect_memberships')); - if( this.get('person') ) this.person = new app.models.Person(this.get('person')); + this.aspectMemberships = new app.collections.AspectMemberships(this.get("aspect_memberships")); + if(this.get("person")) { this.person = new app.models.Person(this.get("person")); } }, inAspect : function(id) { - return this.aspect_memberships.any(function(membership){ return membership.get('aspect').id === id; }); + return this.aspectMemberships.any(function(membership){ return membership.get("aspect").id === id; }); } }); // @license-end diff --git a/app/assets/javascripts/app/pages/contacts.js b/app/assets/javascripts/app/pages/contacts.js index 88eaf46f5..86f7c20fb 100644 --- a/app/assets/javascripts/app/pages/contacts.js +++ b/app/assets/javascripts/app/pages/contacts.js @@ -99,24 +99,49 @@ app.pages.Contacts = Backbone.View.extend({ }); }, - 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); + updateBadgeCount: function(selector, change) { + var count = parseInt($("#aspect_nav " + selector + " .badge").text(), 10); + $("#aspect_nav " + selector + " .badge").text(count + change); }, addAspectMembership: function(data) { - if(data.startSharing) { this.updateContactCount(1); } - this.updateAspectMembershipCount(data.membership.aspectId, 1); + if(data.startSharing) { + this.updateBadgeCount(".all_aspects", 1); + + var contact = this.stream.collection.find(function(c) { + return c.get("person").id === data.membership.personId; + }); + + if(contact && contact.person.get("relationship") === "sharing") { + contact.person.set({relationship: "mutual"}); + this.updateBadgeCount(".only_sharing", -1); + } + else if(contact && contact.person.get("relationship") === "not_sharing") { + contact.person.set({relationship: "receiving"}); + this.updateBadgeCount(".all_contacts", 1); + } + } + this.updateBadgeCount("[data-aspect-id='" + data.membership.aspectId + "']", 1); }, removeAspectMembership: function(data) { - if(data.stopSharing) { this.updateContactCount(-1); } - this.updateAspectMembershipCount(data.membership.aspectId, -1); + if(data.stopSharing) { + this.updateBadgeCount(".all_aspects", -1); + + var contact = this.stream.collection.find(function(c) { + return c.get("person").id === data.membership.personId; + }); + + if(contact && contact.person.get("relationship") === "mutual") { + contact.person.set({relationship: "sharing"}); + this.updateBadgeCount(".only_sharing", 1); + } + else if(contact && contact.person.get("relationship") === "receiving") { + contact.person.set({relationship: "not_sharing"}); + this.updateBadgeCount(".all_contacts", -1); + } + } + this.updateBadgeCount("[data-aspect-id='" + data.membership.aspectId + "']", -1); } }); // @license-end diff --git a/app/assets/javascripts/app/views/contact_view.js b/app/assets/javascripts/app/views/contact_view.js index 05c4c4c6a..5277d65cc 100644 --- a/app/assets/javascripts/app/views/contact_view.js +++ b/app/assets/javascripts/app/views/contact_view.js @@ -37,8 +37,8 @@ app.views.Contact = app.views.Base.extend({ addContactToAspect: function(){ 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({ + var startSharing = this.model.aspectMemberships.length === 0; + this.model.aspectMemberships.create({ "person_id": this.model.get("person_id"), "aspect_id": app.aspect.get("id") },{ @@ -62,8 +62,8 @@ app.views.Contact = app.views.Base.extend({ removeContactFromAspect: function(){ 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 + var stopSharing = this.model.aspectMemberships.length <= 1; + this.model.aspectMemberships .find(function(membership){ return membership.get("aspect").id === app.aspect.id; }) .destroy({ success: function(){ diff --git a/spec/controllers/jasmine_fixtures/contacts_spec.rb b/spec/controllers/jasmine_fixtures/contacts_spec.rb index 6311c3b34..11207e0f6 100644 --- a/spec/controllers/jasmine_fixtures/contacts_spec.rb +++ b/spec/controllers/jasmine_fixtures/contacts_spec.rb @@ -17,6 +17,7 @@ describe ContactsController, :type => :controller do it "generates the aspects_manage fixture", :fixture => true do get :index, :a_id => @aspect.id save_fixture(html_for("body"), "aspects_manage") + save_fixture(controller.gon.preloads[:contacts].to_json, "aspects_manage_contacts_json") end it "generates the contacts_json fixture", :fixture => true do diff --git a/spec/javascripts/app/pages/contacts_spec.js b/spec/javascripts/app/pages/contacts_spec.js index b0bca9d73..e961aaaf6 100644 --- a/spec/javascripts/app/pages/contacts_spec.js +++ b/spec/javascripts/app/pages/contacts_spec.js @@ -1,9 +1,12 @@ describe("app.pages.Contacts", function(){ beforeEach(function() { spec.loadFixture("aspects_manage"); + var contactsData = spec.readFixture("aspects_manage_contacts_json"); + app.contacts = new app.collections.Contacts(JSON.parse(contactsData)); this.view = new app.pages.Contacts({ stream: { - render: function(){} + render: function(){}, + collection: app.contacts } }); Diaspora.I18n.load({ @@ -99,32 +102,30 @@ describe("app.pages.Contacts", function(){ }); }); - describe("updateAspectMembershipCount", function() { + describe("updateBadgeCount", 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); + this.view.updateBadgeCount("[data-aspect-id='" + 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); + this.view.updateBadgeCount("[data-aspect-id='" + 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); + this.view.updateBadgeCount(".all_aspects", 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); + this.view.updateBadgeCount(".all_aspects", -15); expect($("#aspect_nav .all_aspects .badge").text()).toBe("27"); }); }); @@ -132,57 +133,80 @@ describe("app.pages.Contacts", function(){ describe("addAspectMembership", function() { context("when the user starts sharing", function() { beforeEach(function() { + this.contact = app.contacts.first(); this.data = { - membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") }, + membership: { + aspectId: $("#aspect_nav .aspect").eq(1).data("aspect-id"), + personId: this.contact.person.id + }, startSharing: true }; + spyOn(this.view, "updateBadgeCount").and.callThrough(); }); it("is called on aspect_membership:create", function() { spyOn(app.pages.Contacts.prototype, "addAspectMembership"); - this.view = new app.pages.Contacts({stream: {render: function(){}}}); + this.view = new app.pages.Contacts({stream: {render: function(){}, collection: app.contacts}}); 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"); + it("calls updateContactCount for 'all aspects'", function() { this.view.addAspectMembership(this.data); - expect(this.view.updateContactCount).toHaveBeenCalledWith(1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".all_aspects", 1); }); - it("calls updateAspectMembershipCount", function() { - spyOn(this.view, "updateAspectMembershipCount"); + it("calls updateBadgeCount for the aspect", function() { this.view.addAspectMembership(this.data); - expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, 1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith( + "[data-aspect-id='" + this.data.membership.aspectId + "']", 1 + ); + }); + + it("calls updateContactCount for 'all contacts' if there was no relationship before", function() { + this.contact.person.set({relationship: "not_sharing"}); + this.view.addAspectMembership(this.data); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".all_contacts", 1); + expect(this.contact.person.get("relationship")).toBe("receiving"); + }); + + it("calls updateContactCount for 'only sharing' if the relationship was 'sharing'", function() { + this.contact.person.set({relationship: "sharing"}); + this.view.addAspectMembership(this.data); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".only_sharing", -1); + expect(this.contact.person.get("relationship")).toBe("mutual"); }); }); context("when the user doesn't start sharing", function() { beforeEach(function() { this.data = { - membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") }, + membership: { + aspectId: $("#aspect_nav .aspect").eq(1).data("aspect-id"), + personId: app.contacts.first().person.id + }, startSharing: false }; + spyOn(this.view, "updateBadgeCount").and.callThrough(); }); it("is called on aspect_membership:create", function() { spyOn(app.pages.Contacts.prototype, "addAspectMembership"); - this.view = new app.pages.Contacts({stream: {render: function(){}}}); + this.view = new app.pages.Contacts({stream: {render: function(){}, collection: app.contacts}}); 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"); + it("doesn't call updateBadgeCount for 'all aspects'", function() { this.view.addAspectMembership(this.data); - expect(this.view.updateContactCount).not.toHaveBeenCalled(); + expect(this.view.updateBadgeCount).not.toHaveBeenCalledWith(".all_aspects", 1); }); - it("calls updateAspectMembershipCount", function() { - spyOn(this.view, "updateAspectMembershipCount"); + it("calls updateBadgeCount for the aspect", function() { this.view.addAspectMembership(this.data); - expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, 1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith( + "[data-aspect-id='" + this.data.membership.aspectId + "']", 1 + ); }); }); }); @@ -190,57 +214,80 @@ describe("app.pages.Contacts", function(){ describe("removeAspectMembership", function() { context("when the user stops sharing", function() { beforeEach(function() { + this.contact = app.contacts.first(); this.data = { - membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") }, + membership: { + aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id"), + personId: this.contact.person.id + }, stopSharing: true }; + spyOn(this.view, "updateBadgeCount").and.callThrough(); }); it("is called on aspect_membership:destroy", function() { spyOn(app.pages.Contacts.prototype, "removeAspectMembership"); - this.view = new app.pages.Contacts({stream: {render: function(){}}}); + this.view = new app.pages.Contacts({stream: {render: function(){}, collection: app.contacts}}); 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"); + it("calls updateContactCount for 'all aspects'", function() { this.view.removeAspectMembership(this.data); - expect(this.view.updateContactCount).toHaveBeenCalledWith(-1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".all_aspects", -1); }); - it("calls updateAspectMembershipCount", function() { - spyOn(this.view, "updateAspectMembershipCount"); + it("calls updateBadgeCount for the aspect", function() { this.view.removeAspectMembership(this.data); - expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, -1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith( + "[data-aspect-id='" + this.data.membership.aspectId + "']", -1 + ); + }); + + it("calls updateContactCount for 'all contacts' if the relationship was 'receiving'", function() { + this.contact.person.set({relationship: "receiving"}); + this.view.removeAspectMembership(this.data); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".all_contacts", -1); + expect(this.contact.person.get("relationship")).toBe("not_sharing"); + }); + + it("calls updateContactCount for 'only sharing' if the relationship was 'mutual'", function() { + this.contact.person.set({relationship: "mutual"}); + this.view.removeAspectMembership(this.data); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith(".only_sharing", 1); + expect(this.contact.person.get("relationship")).toBe("sharing"); }); }); context("when the user doesn't stop sharing", function() { beforeEach(function() { this.data = { - membership: { aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id") }, + membership: { + aspectId: $("#aspect_nav .aspect").eq(0).data("aspect-id"), + personId: app.contacts.first().person.id + }, stopSharing: false }; + spyOn(this.view, "updateBadgeCount").and.callThrough(); }); it("is called on aspect_membership:destroy", function() { spyOn(app.pages.Contacts.prototype, "removeAspectMembership"); - this.view = new app.pages.Contacts({stream: {render: function(){}}}); + this.view = new app.pages.Contacts({stream: {render: function(){}, collection: app.contacts}}); 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"); + it("doesn't call updateBadgeCount for 'all aspects'", function() { this.view.removeAspectMembership(this.data); - expect(this.view.updateContactCount).not.toHaveBeenCalled(); + expect(this.view.updateBadgeCount).not.toHaveBeenCalledWith(".all_aspects", -1); }); - it("calls updateAspectMembershipCount", function() { - spyOn(this.view, "updateAspectMembershipCount"); + it("calls updateBadgeCount for the aspect", function() { this.view.removeAspectMembership(this.data); - expect(this.view.updateAspectMembershipCount).toHaveBeenCalledWith(this.data.membership.aspectId, -1); + expect(this.view.updateBadgeCount).toHaveBeenCalledWith( + "[data-aspect-id='" + this.data.membership.aspectId + "']", -1 + ); }); }); }); diff --git a/spec/javascripts/app/views/contact_view_spec.js b/spec/javascripts/app/views/contact_view_spec.js index 56ac4ed2a..709882058 100644 --- a/spec/javascripts/app/views/contact_view_spec.js +++ b/spec/javascripts/app/views/contact_view_spec.js @@ -36,8 +36,8 @@ describe("app.views.Contact", function(){ this.view.render(); this.button = this.view.$el.find('.contact_add-to-aspect'); this.contact = this.view.$el.find('.stream_element.contact'); - this.aspect_membership = {id: 42, aspect: app.aspect.toJSON()}; - this.response = JSON.stringify(this.aspect_membership); + this.aspectMembership = {id: 42, aspect: app.aspect.toJSON()}; + this.response = JSON.stringify(this.aspectMembership); }); it('sends a correct ajax request', function() { @@ -48,13 +48,13 @@ describe("app.views.Contact", function(){ }); it('adds a aspect_membership to the contact', function() { - expect(this.model.aspect_memberships.length).toBe(1); + expect(this.model.aspectMemberships.length).toBe(1); $('.contact_add-to-aspect',this.contact).trigger('click'); jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, // success responseText: this.response }); - expect(this.model.aspect_memberships.length).toBe(2); + expect(this.model.aspectMemberships.length).toBe(2); }); it("triggers aspect_membership:create", function() { @@ -101,25 +101,25 @@ describe("app.views.Contact", function(){ this.view.render(); this.button = this.view.$el.find('.contact_remove-from-aspect'); this.contact = this.view.$el.find('.stream_element.contact'); - this.aspect_membership = this.model.aspect_memberships.first().toJSON(); - this.response = JSON.stringify(this.aspect_membership); + this.aspectMembership = this.model.aspectMemberships.first().toJSON(); + this.response = JSON.stringify(this.aspectMembership); }); it('sends a correct ajax request', function() { $('.contact_remove-from-aspect',this.contact).trigger('click'); expect(jasmine.Ajax.requests.mostRecent().url).toBe( - "/aspect_memberships/"+this.aspect_membership.id + "/aspect_memberships/"+this.aspectMembership.id ); }); it('removes the aspect_membership from the contact', function() { - expect(this.model.aspect_memberships.length).toBe(1); + expect(this.model.aspectMemberships.length).toBe(1); $('.contact_remove-from-aspect',this.contact).trigger('click'); jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, // success responseText: this.response }); - expect(this.model.aspect_memberships.length).toBe(0); + expect(this.model.aspectMemberships.length).toBe(0); }); it("triggers aspect_membership:destroy", function() {