From 19b5f6a56291e013b925ed7c812d90ee1bad6136 Mon Sep 17 00:00:00 2001 From: Manvil George Date: Wed, 6 May 2020 12:33:49 +1000 Subject: [PATCH] Handling multiple enterprises at the same location Changes: * Introduced a cluster marker to denote multiple points of interest at the same location * Seperated out a plain enterprise modal into 2 parts * A modal called EnterpriseModal for showing a list of enterprises at the same location * A box called EnterpriseBox(which by the way is also a technically a modal) that shows the details of that particular enterprise selected * If at a location there exists only a single enterprise then only the box is shown --- DOCKER.md | 1 + app/assets/images/map_009-cluster.svg | 104 ++++++++++++++++++ .../services/enterprise_box.js.coffee | 12 ++ .../services/enterprise_modal.js.coffee | 15 +-- .../darkswarm/services/map.js.coffee | 45 ++++++-- .../services/map_configuration.js.coffee | 1 + .../templates/enterprise_box.html.haml | 5 + .../templates/enterprise_modal.html.haml | 5 +- .../partials/enterprise_listing.html.haml | 10 ++ .../darkswarm/modal-enterprises.css.scss | 25 +++++ .../darkswarm/services/map_spec.js.coffee | 42 ++++++- 11 files changed, 240 insertions(+), 25 deletions(-) create mode 100644 app/assets/images/map_009-cluster.svg create mode 100644 app/assets/javascripts/darkswarm/services/enterprise_box.js.coffee create mode 100644 app/assets/javascripts/templates/enterprise_box.html.haml create mode 100644 app/assets/javascripts/templates/partials/enterprise_listing.html.haml diff --git a/DOCKER.md b/DOCKER.md index 3df0f7d345..a1e56fb4d9 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -39,6 +39,7 @@ Setup the database and seed it with sample data: ```sh $ docker-compose run web bundle exec rake db:reset $ docker-compose run web bundle exec rake db:test:prepare +$ docker-compose run web bundle exec rake db:seed $ docker-compose run web bundle exec rake ofn:sample_data ``` diff --git a/app/assets/images/map_009-cluster.svg b/app/assets/images/map_009-cluster.svg new file mode 100644 index 0000000000..3c1813c5e1 --- /dev/null +++ b/app/assets/images/map_009-cluster.svg @@ -0,0 +1,104 @@ + + + + + + + +image/svg+xml + + + + + + + + + 1+ + + + diff --git a/app/assets/javascripts/darkswarm/services/enterprise_box.js.coffee b/app/assets/javascripts/darkswarm/services/enterprise_box.js.coffee new file mode 100644 index 0000000000..0445dbb4f1 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/enterprise_box.js.coffee @@ -0,0 +1,12 @@ +Darkswarm.factory "EnterpriseBox", ($modal, $rootScope, $http)-> + # Build a modal popup for an enterprise. + new class EnterpriseBox + open: (enterprise)-> + scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise + scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1 + + $http.get("/api/shops/" + enterprise.id).success (data) -> + scope.enterprise = data + $modal.open(templateUrl: "enterprise_box.html", scope: scope) + .error (data) -> + console.error(data) diff --git a/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee b/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee index 37dafef776..623b924970 100644 --- a/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee @@ -1,12 +1,13 @@ -Darkswarm.factory "EnterpriseModal", ($modal, $rootScope, $http)-> +Darkswarm.factory "EnterpriseModal", ($modal, $rootScope, $http, EnterpriseBox)-> # Build a modal popup for an enterprise. new class EnterpriseModal - open: (enterprise)-> + open: (enterprises)-> scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise scope.embedded_layout = window.location.search.indexOf("embedded_shopfront=true") != -1 - - $http.get("/api/shops/" + enterprise.id).success (data) -> - scope.enterprise = data + scope.enterprises = enterprises + scope.EnterpriseBox = EnterpriseBox + len = Object.keys(enterprises).length + if len > 1 $modal.open(templateUrl: "enterprise_modal.html", scope: scope) - .error (data) -> - console.error(data) + else + EnterpriseBox.open enterprises[Object.keys(enterprises)[0]] diff --git a/app/assets/javascripts/darkswarm/services/map.js.coffee b/app/assets/javascripts/darkswarm/services/map.js.coffee index 45370061fd..9c98f5c09b 100644 --- a/app/assets/javascripts/darkswarm/services/map.js.coffee +++ b/app/assets/javascripts/darkswarm/services/map.js.coffee @@ -1,21 +1,42 @@ -Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal) -> +Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, MapConfiguration) -> new class OfnMap constructor: -> - @enterprises = @enterprise_markers(Enterprises.enterprises) + @coordinates = {} + @enterprises = Enterprises.enterprises.filter (enterprise) -> + # Remove enterprises w/o lat or long + enterprise.latitude != null || enterprise.longitude != null + @enterprises = @enterprise_markers(@enterprises) + self = this @enterprises = @enterprises.filter (enterprise) -> - enterprise.latitude != null || enterprise.longitude != null # Remove enterprises w/o lat or long + # Remove enterprises w/o lat or long + enterprise.latitude != null || enterprise.longitude != null enterprise_markers: (enterprises) -> @extend(enterprise) for enterprise in enterprises + enterprise_hash: (hash, enterprise) -> + hash[enterprise.id] = { id: enterprise.id, name: enterprise.name, icon: enterprise.icon_font } + hash + + # Adding methods to each enterprise extend: (enterprise) -> - new class MapMarker - # We cherry-pick attributes because GMaps tries to crawl - # our data, and our data is cyclic, so it breaks - latitude: enterprise.latitude - longitude: enterprise.longitude - icon: enterprise.icon - id: enterprise.id - reveal: => - EnterpriseModal.open enterprise + marker = @coordinates[[enterprise.latitude, enterprise.longitude]] + self = this + if !marker + marker = new class MapMarker + # We cherry-pick attributes because GMaps tries to crawl + # our data, and our data is cyclic, so it breaks + latitude: enterprise.latitude + longitude: enterprise.longitude + icon: enterprise.icon + id: [enterprise.id] + enterprises: self.enterprise_hash({}, enterprise) + reveal: => + EnterpriseModal.open this.enterprises + @coordinates[[enterprise.latitude, enterprise.longitude]] = marker + else + marker.icon = MapConfiguration.options.cluster_icon + self.enterprise_hash(marker.enterprises, enterprise) + marker.id.push(enterprise.id) + marker diff --git a/app/assets/javascripts/darkswarm/services/map_configuration.js.coffee b/app/assets/javascripts/darkswarm/services/map_configuration.js.coffee index 1979affeab..93e4104f0a 100644 --- a/app/assets/javascripts/darkswarm/services/map_configuration.js.coffee +++ b/app/assets/javascripts/darkswarm/services/map_configuration.js.coffee @@ -4,6 +4,7 @@ Darkswarm.factory "MapConfiguration", -> center: latitude: -37.4713077 longitude: 144.7851531 + cluster_icon: 'assets/map_009-cluster.svg' zoom: 12 additional_options: # mapTypeId: 'satellite' diff --git a/app/assets/javascripts/templates/enterprise_box.html.haml b/app/assets/javascripts/templates/enterprise_box.html.haml new file mode 100644 index 0000000000..350cd6ed80 --- /dev/null +++ b/app/assets/javascripts/templates/enterprise_box.html.haml @@ -0,0 +1,5 @@ +%ng-include{src: "'partials/enterprise_header.html'"} +%ng-include{src: "'partials/enterprise_details.html'"} +%ng-include{src: "'partials/hub_details.html'"} +%ng-include{src: "'partials/producer_details.html'"} +%ng-include{src: "'partials/close.html'"} diff --git a/app/assets/javascripts/templates/enterprise_modal.html.haml b/app/assets/javascripts/templates/enterprise_modal.html.haml index 350cd6ed80..046029d829 100644 --- a/app/assets/javascripts/templates/enterprise_modal.html.haml +++ b/app/assets/javascripts/templates/enterprise_modal.html.haml @@ -1,5 +1,2 @@ -%ng-include{src: "'partials/enterprise_header.html'"} -%ng-include{src: "'partials/enterprise_details.html'"} -%ng-include{src: "'partials/hub_details.html'"} -%ng-include{src: "'partials/producer_details.html'"} +%ng-include{src: "'partials/enterprise_listing.html'"} %ng-include{src: "'partials/close.html'"} diff --git a/app/assets/javascripts/templates/partials/enterprise_listing.html.haml b/app/assets/javascripts/templates/partials/enterprise_listing.html.haml new file mode 100644 index 0000000000..b22223ede9 --- /dev/null +++ b/app/assets/javascripts/templates/partials/enterprise_listing.html.haml @@ -0,0 +1,10 @@ +.modal-list + .row{"ng-repeat" => "(id, enterprise) in ::enterprises"} + .highlight + .highlight-top.row.enterprise + .small-12.medium-12.large-12.columns + %h4 + %a.heading{"ng-click" => "::EnterpriseBox.open(enterprise)"} + %i{"ng-class" => "enterprise.icon"} + %span{"ng-bind" => "enterprise.name"} + %img.hero-img{"ng-src" => "{{::enterprise.promo_image}}"} diff --git a/app/assets/stylesheets/darkswarm/modal-enterprises.css.scss b/app/assets/stylesheets/darkswarm/modal-enterprises.css.scss index 5d356028f8..0c2e844828 100644 --- a/app/assets/stylesheets/darkswarm/modal-enterprises.css.scss +++ b/app/assets/stylesheets/darkswarm/modal-enterprises.css.scss @@ -1,5 +1,6 @@ @import "branding"; @import "mixins"; +@import "admin/globals/variables"; // Generic styles for use @@ -22,6 +23,24 @@ margin-bottom: 0.5rem; } +.modal-list { + text-align: center; + font-size: 1rem; + font-weight: 400; + border-bottom: 1px solid $light-grey; + margin-top: 0.75rem; + margin-bottom: 0.5rem; + + a.heading { + color: $color-link; + + &:hover { + color: $color-link-hover; + text-decoration: underline; + } + } +} + // Enterprise promo image and text .highlight { @@ -54,6 +73,12 @@ color: $clr-brick; } + &.enterprise { + margin: auto; + text-align: center; + width: 100%; + } + p { line-height: 2.4; diff --git a/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee index 669f0ca74d..fb4def8342 100644 --- a/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee @@ -6,6 +6,8 @@ describe "Hubs service", -> { id: 2 active: false + icon_font: 'abc' + name: 'BugSpray' orders_close_at: new Date() type: "hub" visible: true @@ -15,12 +17,36 @@ describe "Hubs service", -> { id: 3 active: false + icon_font: 'def' + name: 'Toothbrush' + orders_close_at: new Date() + type: "hub" + visible: true + latitude: 100 + longitude: 200 + } + { + id: 4 + active: false + icon_font: 'ghi' + name: 'Covidness' orders_close_at: new Date() type: "hub" visible: true latitude: null longitude: null } + { + id: 5 + active: false + icon_font: 'jkl' + name: 'Toothbrush for kids' + orders_close_at: new Date() + type: "hub" + visible: true + latitude: 100 + longitude: 200 + } ] beforeEach -> @@ -34,7 +60,19 @@ describe "Hubs service", -> OfnMap = $injector.get("OfnMap") it "builds MapMarkers from enterprises", -> - expect(OfnMap.enterprises[0].id).toBe enterprises[0].id + expect(OfnMap.enterprises[0].id[0]).toBe enterprises[0].id it "excludes enterprises without latitude or longitude", -> - expect(OfnMap.enterprises.map (e) -> e.id).not.toContain enterprises[1].id + expect(OfnMap.enterprises.map (e) -> e.id).not.toContain [enterprises[2].id] + + it "the MapMarkers will a field for enterprises", -> + enterprise = enterprises[0] + expect(OfnMap.enterprises[0].enterprises[enterprise.id]).toEqual { id: enterprise.id, name: enterprise.name, icon: enterprise.icon_font } + + it "the MapMarkers will bunch up enterprises with the same coordinates", -> + enterprise1 = enterprises[1] + enterprise2 = enterprises[3] + hash = {} + hash[enterprise1.id] = { id: enterprise1.id, name: enterprise1.name, icon: enterprise1.icon_font } + hash[enterprise2.id] = { id: enterprise2.id, name: enterprise2.name, icon: enterprise2.icon_font } + expect(OfnMap.enterprises[2].enterprises).toEqual hash