     (if (empty? (:items @trolley-state))
       [bootstrap/list-group-item {:key 0 :list-item true}
        [:em "Nothing in your trolley, yet!"]]
-      (map-indexed
-       (fn [idx item]
-         ^{:key idx}
-         [trolley-item idx item
-          (partial remove-item-from-trolley trolley-state idx)
+      (map
+       (fn [item]
+         ^{:key (:id item)}
+         [trolley-item item
+          (partial remove-item-from-trolley trolley-state (:id item))
           #(swap! trolley-state update-in [:items] conj item)])
-       (:items @trolley-state)))]])
+       (group-items (:items @trolley-state))))]])
 
 (defn select-items-view
   [trolley-state progress-fn]


(defn package-total-overlay
  [packages]
  [bootstrap/pop-over {:id "package-popover" :title (str (count packages) " packages")
                       :placement :bottom}
   "This product comes in " (count packages) " packages"])

(defn package-total-view
  [item-container packages]

                           :bs-style :danger
                           :on-click remove-fn}
         [bootstrap/glyph {:glyph :remove}] " Remove"]]]]
     [:div
      [package-total-view (reagent/current-component) packages]
      (when-not (and count (>= 1 count))
        [:h2 "⨉" count])]]
    [:div.preview
     [bootstrap/thumbnail {:src image-src :responsive true}]]]])

(defn- remove-first
  "remove the first item in the coll where the value of k matches v"
  [coll k v]
  (let [first-part (take-while #(not= (k %) v) coll)]
    (concat
     first-part
     (take-last (dec (- (count coll) (count first-part))) coll))))

(defn- remove-item-from-trolley
  [trolley-state id]
  (let [items (:items @trolley-state)]
    (swap! trolley-state update-in [:items]
           remove-first :id id)))

(defn- group-items
  [items]
  (let [grouped (group-by :id items)]
    (map (fn [[id items]]
           (assoc (first items) :count (count items)))
         grouped)))

(defn trolley-list-contents
  [trolley-state]
