Gift list dev diary: gift list navigation

All development for this project is shared on github at https://github.com/codonnell/mygiftlist-blog. I will endeavor to focus on the most relevant snippets of code rather than go over all of them on this blog. For interested parties, the github repo is available to survey all of the minor details.

In this post we’ll implement a navbar that enables navigation to placeholder gift list pages. The main novelty required is loading gift list data so we can render the navbar on load and the use of a parameterized route. The full changeset can be found in this commit.

We’re going to add a navbar component on the left side of the page when users are logged in which shows the gift lists the user created. Since we implemented a :created-gift-lists query in the last post, we only need to write the components.

(defsc CreatedGiftListItem [this {::gift-list/keys [id name]}]
  {:query [::gift-list/id ::gift-list/name]
   :ident ::gift-list/id}
  (dom/a :.item {:onClick #(comp/transact! this [(routing/route-to
                                                   {:path ["gift-list" id]})])}
    (dom/div {} name)))

(defsc LeftNav [_this {:keys [created-gift-lists]}]
  {:query [{:created-gift-lists (comp/get-query CreatedGiftListItem)}]
   :ident (fn [] [:component/id :left-nav])
   :initial-state {:created-gift-lists []}}
  (dom/div :.ui.vertical.menu
    (dom/div :.item
      (dom/div :.header "Created Gift Lists")
      (mapv ui-created-gift-list-item created-gift-lists))))

We will also implement a placeholder gift list page so we have something to which we can navigate.

(defsc GiftList [_this {::gift-list/keys [name]}]
  {:query [::gift-list/id ::gift-list/name]
   :ident ::gift-list/id
   :route-segment ["gift-list" ::gift-list/id]
   :will-enter (fn [_ {::gift-list/keys [id]}]
                 (dr/route-immediate [::gift-list/id (uuid id)]))}
  (dom/div
    (dom/h3 name)))

This is very similar to our previous routing targets with the exception that it has a parameter. In the route-segment we have a ::gift-list/id keyword to indicate that the URL should look like /gift-list/1d512b0b-94a2-4035-9f92-c61ebd3f40db and that we can access the gift list id in the second argument to :will-enter under the ::gift-list/id key. All route parameters are received as strings, so we must coerce it to a uuid in :will-enter to have a properly formed ident. I often forget this and get confused why the page isn’t displaying what I expect it to.

Fetch data

Lastly, we need to be sure to fetch data to populate our navbar on page load. We will accomplish this by adding a call to df/load! to our init function. If the user adds more gift lists, we will keep our app state updated in the local mutation action. Here’s what our new init function looks like:

(defn ^:export init []
  (log/info "Application starting...")
  (app/mount! SPA ui.root/Root "app")
  (go
    (<! (auth/create-auth0-client!))
    (when (is-redirect?)
      (<! (auth/handle-redirect-callback))
      (clear-query-params!))
    (let [authenticated (<! (auth/is-authenticated?))]
      (comp/transact! SPA [(set-authenticated
                             {:authenticated authenticated})])
      (routing/start!)
      (if authenticated
        (do (df/load! SPA [:component/id :left-nav] ui.nav/LeftNav)
            (let [{:keys [sub email]} (<! (auth/get-user-info))]
              (comp/transact! SPA [(m.user/set-current-user
                                     #::user{:id (tempid/tempid)
                                             :auth0-id sub
                                             :email email})])))
        (comp/transact! SPA
          [(routing/route-to {:path (dr/path-to ui.root/LoginForm)})])))))

And that’s all! We can now navigate to gift list pages.

Prev: Gift list dev diary: gift list form and listing Next: Gift list dev diary: deployment