Skip to content

Instantly share code, notes, and snippets.

@Alex-Bakic
Created November 12, 2019 02:42
Show Gist options
  • Save Alex-Bakic/ed01b24ab47d35e3e3fffda1a34bf3be to your computer and use it in GitHub Desktop.
Save Alex-Bakic/ed01b24ab47d35e3e3fffda1a34bf3be to your computer and use it in GitHub Desktop.
# Extension of issue 6 , to do with reloading and the hidden bug highlighted in the /job common page.
The reloading of recommended jobs and the dashboard is currently solved, though leaving the applied page out has left bugs, and ones similiar to those in the last issue which is where we find a job in liked without the "liked" selected indication. This is partly because we don't re-render, but there is another issue underlying this one. Let's first take a look at the `page` function within `wh.logged-in.personalised-jobs.views`:
(defn page [type-of-jobs]
(into
[:div.main
[:div.spread-or-stack
[:h1 (str (-> type-of-jobs name str/capitalize)) " Jobs"]
(when (= type-of-jobs :recommended)
[:div.has-bottom-margin
[link [:button.button "Improve recommendations"] :improve-recommendations :class "level-item"]])]]
(let [parts (partition-all 3 (<sub [::subs/jobs]))
has-applied? (some? (<sub [:user/applied-jobs]))]
(cond
(seq parts) (conj (vec (for [part parts]
(into [:div.columns]
(for [job part]
[:div.column.is-4
[job-card job (merge {:user-has-applied? has-applied?
:logged-in? true}
(when (= type-of-jobs :recommended)
{:on-close :reload-recommended})
(when (= type-of-jobs :liked)
{:on-close :reload-liked}))]]))))
[:div.columns.is-centered.load-more-section
[:div.column.is-4.has-text-centered
(when (<sub [::subs/show-load-more?])
[:button.button {:on-click #(dispatch [::events/load-more type-of-jobs])} "Load more Jobs"])]])
:else (case type-of-jobs
:recommended [[:p "Add some skills and preffered locations to your profile to see recommendations."]]
:liked [[:p "Click on some " [icon "like" :class "like red-fill"] " to save jobs you like."]]
:applied [[:p "You haven't applied for any jobs yet... " [link "What are you waiting for?" :jobsboard :class "a--underlined"] "."]]
[[:p "No jobs found."]])))))
The "parts" data, that gather information from `::subs/jobs`, is never *strictly limited to that type of page* as graphql will simply tag each job with the approriate "is it an applied or a liked job?" check. But nothing stops those jobs from still being in that group. We notice the implications of this when we use this page function for our liked jobs page, only to see "unliked" jobs slither through and become rendered. Cases where they do slither through are highlighted below, and this is to do with the "/job/*job-slug*" page and the like icon on that page. Due to the current fixes I administered to the `:wh.events/toggle-job-like` event, it meant that it required an `action` as an argument, so that it knows which page to reload, but we don't want to reload the page detailing the job, just because the user clicked like. Nothing new is being re-rendered.
;; within the client/common-pages/src/wh/job/views.cljc file
;; notice the "action" arg is left, and is for all such components at the moment ...
(defn like-icon [class]
[icon "job-heart"
:class (util/merge-classes class
(when (<sub [::subs/liked?]) (str class "--liked")))
:on-click #(dispatch [:wh.events/toggle-job-like
{:id (<sub [::subs/id])
:company-name (<sub [::subs/company-name])
:title (<sub [::subs/title])}])])
What we can do is just include a `:none` arg ... which isn't pretty as it means that components will have to be aware of the functionality of `::toggle-job-like` , which isn't ideal :/
And we need to modify the `::toggle-job-like-success` event itself to allow for such cases:
;; within the client/client/src/wh/events.cljs file
(reg-event-fx
::toggle-job-like-success
db/default-interceptors
(fn [{db :db} [id action]]
{:db (update-in db [:wh.user.db/sub-db :wh.user.db/liked-jobs] util/toggle id)
:dispatch (case action
:reload-recommended [:personalised-jobs/fetch-jobs-by-type :recommended 1]
:reload-liked [:personalised-jobs/fetch-jobs-by-type :liked 1]
:reload-dashboard [:wh.logged-in.dashboard.events/fetch-recommended-jobs]
;; don't fire anything in the case of such components...
[])}))
Now that will allow the icon to work correctly, but it doesn't change the structure of the `::subs/jobs` subscription in any way, and as long it only tags jobs it means all sorts of bugs are possible, with jobs of different sections being included in the same vector. What we can do is wrap a filtering subscription around `::subs/jobs` , as the tagging functionality *is important*, as it is at the stage that `page` is instantiated that we will need a marker.
;; unsure what to call these, as :user/liked-jobs is a sub,
;; but as they're namespaced separated , it isn't an IMMEDIATE issue...
(reg-sub
::liked-jobs
:<- [::jobs]
(fn [all-jobs]
(filterv :liked all-jobs)))
(reg-sub
::applied-jobs
:<- [::jobs]
(fn [all-jobs]
(filterv :applied all-jobs)))
(reg-sub
::recommended-jobs
:<- [::jobs]
(fn [all-jobs]
(::personalised-jobs/jobs all-jobs)))
Now to go into page and narrow down the data we need , and to keep all the different sections separated. I began by defining a few helper functions for each unique property of applied, liked and recommended:
;; helper for deciding the value of "action", narrowing down which page should be reloaded by
;; the like and blacklist events in client/src/wh/events.cljs
(defn on-close
[type-of-jobs]
(case type-of-jobs
:recommended {:on-close :reload-recommended}
:applied {:on-close :reload-applied}
:liked {:on-close :reload-liked}
{}))
;; need to specify job db, as the ::subs/jobs is a generalisation too far, as we cannot narrow down the jobs
;; themselves , depending on the type of job is what we work with, and that should be that. Allow the subscription
;; vector to be specified here , allowing page to never "go out of bounds" and avoid such bugs in the future.
(defn specify-subscription
[type-of-jobs]
(case type-of-jobs
:recommended [::subs/recommended-jobs]
:applied [::subs/applied-jobs]
:liked [::subs/liked-jobs]))
(defn message
[type-of-jobs]
(case type-of-jobs
:recommended [[:p "Add some skills and preffered locations to your profile to see recommendations."]]
:liked [[:p "Click on some " [icon "like" :class "like red-fill"] " to save jobs you like."]]
:applied [[:p "You haven't applied for any jobs yet... " [link "What are you waiting for?" :jobsboard :class "a--underlined"] "."]]
[[:p "No jobs found."]]))
But we don't need all these `case` calls , and we can rework this into one , more compact fn:
;; first element is the on-close map, the second element is the relevant job pool , and the third element is the message if page would be empty.
(defn job-type-data
[type-of-jobs]
(case type-of-jobs
:recommended [{:on-close :reload-recommended}
[::subs/recommended-jobs]
[[:p "Add some skills and preffered locations to your profile to see recommendations."]]]
:liked [{:on-close :reload-liked}
[::subs/liked-jobs]
[[:p "Click on some " [icon "like" :class "like red-fill"] " to save jobs you like."]]]
;; nothing gets re-rendered, we're only liking that job
:applied [{:on-close :none}
[::subs/applied-jobs]
[[:p "You haven't applied for any jobs yet... " [link "What are you waiting for?" :jobsboard :class "a--underlined"] "."]]]))
And in page we can just destructure the info we get:
(defn page [type-of-jobs]
(into
[:div.main
[:div.spread-or-stack
[:h1 (str (-> type-of-jobs name str/capitalize)) " Jobs"]
(when (= type-of-jobs :recommended)
[:div.has-bottom-margin
[link [:button.button "Improve recommendations"] :improve-recommendations :class "level-item"]])]]
;; stops us from having to do three case checks , by putting all relevant data per keyword into a vector.
(let [data (job-type-data type-of-jobs)
on-close (first data)
subscription (second data)
message (last data)
;; this allows us to grab the data pertaining to only one type of page.
parts (partition-all 3 (<sub subscription))
has-applied? (some? (<sub [:user/applied-jobs]))]
(cond
(seq parts) (conj (vec (for [part parts]
(into [:div.columns]
(for [job part]
[:div.column.is-4
[job-card job (merge {:user-has-applied? has-applied?
:logged-in? true}
on-close)]]))))
[:div.columns.is-centered.load-more-section
[:div.column.is-4.has-text-centered
(when (<sub [::subs/show-load-more?])
[:button.button {:on-click #(dispatch [::events/load-more type-of-jobs])} "Load more Jobs"])]])
:else (if message
message
[[:p "No jobs found."]])))))
So to recap, there are two fixes here. The first is to include an else clause for case, so that components that like-jobs and blacklist don't have to re-render anything, like the applied jobs page for example. This also allows the like icon in `wh.job.views` to not re-render the page displaying the job. But aside from this, we also remodelled the page component to work closer with each implementation, and by passing to the liked jobs page only the liked jobs, we can chalkf off another set of issues for now :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment