diff --git a/project.clj b/project.clj index 2dd34f1..222481c 100644 --- a/project.clj +++ b/project.clj @@ -8,7 +8,7 @@ [duct/module.logging "0.4.0"] [duct/module.web "0.7.0"] [duct/module.ataraxy "0.3.0"] - [duct/module.cljs "0.4.0" :exclusions [org.clojure/clojurescript]] + [duct/module.cljs "0.4.1" :exclusions [org.clojure/clojurescript]] [duct/module.sql "0.5.0"] [duct/middleware.buddy "0.1.0"] @@ -27,7 +27,7 @@ [org.clojure/core.async "0.4.490"] [org.postgresql/postgresql "42.2.5"]] :middleware [lein-duct.plugin/middleware] - :plugins [[duct/lein-duct "0.11.2"]] + :plugins [[duct/lein-duct "0.12.0"]] :main ^:skip-aot conduit.main :resource-paths ["resources" "target/resources"] :prep-tasks ["javac" "compile" ["run" ":duct/compiler"]] @@ -43,7 +43,7 @@ :resource-paths ["dev/resources"] :dependencies [ ;; cljs [cider/piggieback "0.4.0"] - [walkable/duct.server.figwheel "0.4.0-SNAPSHOT" :exclusions [org.clojure/clojurescript]] + [duct/server.figwheel "0.3.1" :exclusions [org.clojure/clojurescript]] [org.clojure/test.check "0.10.0-alpha3"] [devcards "0.2.6" :exclusions [org.clojure/clojurescript]] diff --git a/resources/conduit/config.edn b/resources/conduit/config.edn index 88857f4..1249528 100644 --- a/resources/conduit/config.edn +++ b/resources/conduit/config.edn @@ -47,8 +47,7 @@ :user/whoami "user" - [:feed.global/articles :feed.global/next-id - :feed.personal/articles :feed.personal/next-id] + [:feed.global/articles :feed.personal/articles] "article" :tags/all @@ -74,14 +73,19 @@ :comment/author [:comment/author-id :user/id]} - :pseudo-columns {:pagination/total [:count-*] - :pagination/last-id [:max :article/id]} + :pseudo-columns {} :aggregators {[:article/liked-by-count :user/followed-by-count :tag/count] [:count-*] - [:feed.global/next-id :feed.personal/next-id] - :article/id + :app.articles.list/total-items + [:count-*] + + :app.articles.list/first-item-id + [:min :article/id] + + :app.articles.list/last-item-id + [:max :article/id] [:user/followed-by-me :article/liked-by-me] [:< 0 [:count-*]]} @@ -91,7 +95,7 @@ :user/articles :article/author} :extra-conditions - {[:feed.personal/articles :feed.personal/next-id] + {[:feed.personal/articles] {:article/author {:user/followed-by [:= app/current-user :user/id]}} :article/liked-by-me diff --git a/src/conduit/handler/mutations.clj b/src/conduit/handler/mutations.clj index abf0ce4..e9a09d5 100644 --- a/src/conduit/handler/mutations.clj +++ b/src/conduit/handler/mutations.clj @@ -124,3 +124,21 @@ (if current-user (article/remove-tag db current-user article-id tag) {}))) + +(defmutation conduit.ui.pagination/next-page [page-ident] + (action [{:keys [parser] :app/keys [db current-user] :as env + list-subquery :query}] + (let [next-page-ident-value (assoc page-ident :app.articles.list.page/operation :next) + next-page-ident [:app.articles/list next-page-ident-value]] + (-> env + (parser [{next-page-ident list-subquery}]) + (get next-page-ident))))) + +(defmutation conduit.ui.pagination/previous-page [page-ident] + (action [{:keys [parser] :app/keys [db current-user] :as env + list-subquery :query}] + (let [next-page-ident-value (assoc page-ident :app.articles.list.page/operation :previous) + next-page-ident [:app.articles/list next-page-ident-value]] + (-> env + (parser [{next-page-ident list-subquery}]) + (get next-page-ident))))) diff --git a/src/conduit/handler/walkable.clj b/src/conduit/handler/walkable.clj index 044e48a..1faa3c3 100644 --- a/src/conduit/handler/walkable.clj +++ b/src/conduit/handler/walkable.clj @@ -11,36 +11,62 @@ [conduit.handler.mutations :as mutations] [fulcro.server :as server :refer [server-mutate]] [com.wsscode.pathom.core :as p] + [conduit.util :as util :refer [list-ident list-ident-value]] [clojure.spec.alpha :as s])) (defn get-items-subquery [query] (->> query - (some #(and (map? %) (get % :pagination/items))))) - -(defn query-params [env] - (let [{:pagination/keys [size start end] :or {size 10}} (env/params env)] - {:order-by [:article/id (if-not (number? end) :desc :asc)] - :filters (cond - (number? end) - [:<= :article/id end] - (number? start) - [:<= start :article/id])})) - -(defn extra-filter [env] - (let [{:pagination/keys [list-type list-id]} (env/params env)] - (case list-type - :liked-articles/by-user-id - {:article/liked-by [:= :user/id list-id]} - - :owned-articles/by-user-id - [:= :article/author-id list-id] - - :articles/by-tag - {:article/tags [:= :tag/tag list-id]} - - ;; default + (some #(and (map? %) (get % :app.articles.list/current-page))) + (some #(and (map? %) (get % :app.articles.list.page/items))))) + +(defn page-filters [{:app.articles.list/keys [direction] + :app.articles.list.page/keys [operation start end]}] + (if (= :forward direction) + (case operation + :current + [:>= start :article/id end] + + :next + [:> end :article/id] + + :previous + [:> :article/id start] + + ;; else + nil) + (case operation + :current + [:<= start :article/id end] + + :next + [:< end :article/id] + + :previous + [:< :article/id start] + + ;; else nil))) +(defn order-by [{:app.articles.list/keys [direction] + :app.articles.list.page/keys [operation]}] + [:article/id (if (and (= direction :forward) (not= operation :previous)) + :desc + :asc)]) + +(defn list-filters [{:app.articles.list/keys [list-type list-id]}] + (case list-type + :app.articles/liked-by-user + {:article/liked-by [:= :user/id list-id]} + + :app.articles/owned-by-user + [:= :article/author-id list-id] + + :app.articles/with-tag + {:article/tags [:= :tag/tag list-id]} + + ;; default + nil)) + (defn merge-filters [xs] (let [xs (remove nil? xs)] (when (seq xs) @@ -48,109 +74,67 @@ (first xs) (into [:and] xs))))) -(defn next-id [env] - (let [{:pagination/keys [list-type list-id size start end] :or {size 10}} (env/params env) - - {:keys [parser query]} env - - query-root - (cond - (= [list-type list-id] [:articles/by-feed :personal]) - :feed.personal/next-id - - :default - :feed.global/next-id) - - params {:order-by [:article/id :desc] - :limit 1 - :offset (when-not (number? end) size) - :filters (merge-filters - [(extra-filter env) - (cond - (number? end) - [:< :article/id end] - (number? start) - [:<= :article/id start])])}] - (-> (parser env [(list query-root params)]) - (get query-root)))) - -(defn previous-id [env] - (let [{:pagination/keys [list-type list-id size start end] :or {size 10}} (env/params env) - - {:keys [parser query]} env - query-root - (cond - (= [list-type list-id] [:articles/by-feed :personal]) - :feed.personal/next-id - - :default - :feed.global/next-id) - - params {:order-by [:article/id :asc] - :limit 1 - :offset (when (number? end) size) - :filters (merge-filters - [(extra-filter env) - (cond - (number? end) - [:<= end :article/id] - (number? start) - [:< start :article/id])])}] - (when (or end start) - (-> (parser env [(list query-root params)]) - (get query-root))))) - -(defn fetch-items [env] - (let [{:pagination/keys [list-type list-id size start end] :or {size 10}} (env/params env) - - {:keys [parser query]} env - - query-root - (cond - (= [list-type list-id] [:articles/by-feed :personal]) - :feed.personal/articles - - :default - :feed.global/articles) - - params {:order-by [:article/id (if (number? end) :asc :desc)] - :limit size - :filters (merge-filters - [(extra-filter env) - (cond - (number? end) - [:<= end :article/id] - (number? start) - [:<= :article/id start])])} - items-query [{(list query-root params) (get-items-subquery query)}]] +(defn fetch-items + [query-root params {:keys [parser query] :as env}] + (let [items-query + [{(list query-root params) (get-items-subquery query)}]] (-> (parser env items-query) (get query-root)))) -(defn paginated-list-resolver [env] - (if (not= :paginated-list/articles (env/dispatch-key env)) +(defn query-root + [{:app.articles.list/keys [list-type list-id]}] + (cond + (= [list-type list-id] [:app.articles/on-feed :personal]) + :feed.personal/articles + + :default + :feed.global/articles)) + +(defn fetch-list-stats + [query-root list-filters {:keys [parser] :as env}] + (let [query [{(list query-root {:filters list-filters}) + [:app.articles.list/first-item-id + :app.articles.list/last-item-id + :app.articles.list/total-items]}]] + (-> (parser env query) + (get query-root) + first))) + +(defn article-list-resolver [env] + (if (not= :app.articles/list (env/dispatch-key env)) + ::p/continue + (let [page (env/ident-value env) + ident-value (list-ident-value page) + direction (:app.articles.list/direction ident-value) + qr (query-root ident-value) + lf (list-filters ident-value) + stats (fetch-list-stats qr lf env) + items (fetch-items qr + {:order-by (order-by ident-value) + :limit (:app.articles.list/size ident-value) + :filters (merge-filters [lf (page-filters page)])} + env)] + (merge ident-value + (clojure.set/rename-keys stats (when (= :forward direction) + {:app.articles.list/first-item-id + :app.articles.list/last-item-id + :app.articles.list/last-item-id + :app.articles.list/first-item-id})) + {:app.articles.list/current-page + (merge ident-value + #:app.articles.list.page {:items items + :start (-> items first :article/id) + :end (-> items last :article/id)})})))) + +(defn whoami-resolver [env] + (if (not= :user/whoami (env/dispatch-key env)) ::p/continue - (let [{:pagination/keys [list-type list-id size start end] :or {size 10}} (env/params env) - - items (fetch-items env)] - (merge - {(if (number? end) :pagination/end :pagination/start) - (or (:article/id (first items)) :no-start)} - #:pagination{:size size - :list-type list-type - :list-id list-id - :next-id (let [n (next-id env)] - (when (number? n) - #:pagination{:list-type list-type - :list-id list-id - :size size - :start n})) - :previous-id (let [p (previous-id env)] - (when (number? p) - #:pagination{:list-type list-type - :list-id list-id - :size size - :end p})) - :items items})))) + (if-let [user-id (:app/current-user env)] + (let [{:keys [parser query]} env + ident [:user/by-id user-id]] + (-> (parser env [{ident query}]) + (get ident))) + #:user {:id :guest :email "non@exist"}))) (def pathom-parser (p/parser @@ -158,7 +142,8 @@ ::p/plugins [(p/env-plugin {::p/reader - [paginated-list-resolver + [article-list-resolver + whoami-resolver sqb/pull-entities p/map-reader p/env-placeholder-reader]})]})) diff --git a/src/conduit/ui/home.cljs b/src/conduit/ui/home.cljs index 3ad88be..a2345f4 100644 --- a/src/conduit/ui/home.cljs +++ b/src/conduit/ui/home.cljs @@ -107,11 +107,10 @@ (def ui-tags (prim/factory Tags)) -(defsc FeedSelector [this props {:keys [current-page]}] - {:query []} - (let [whoami (prim/shared this :user/whoami) - {:pagination/keys [list-type list-id]} current-page - not-logged-in (= :guest (:user/id whoami))] +(defsc FeedSelector [this article-list] + (let [whoami (prim/shared this :user/whoami) + {:app.articles.list/keys [list-type list-id]} article-list + not-logged-in (= :guest (:user/id whoami))] (dom/div :.feed-toggle (dom/ul :.nav.nav-pills.outline-active (when (or (not not-logged-in) @@ -128,84 +127,73 @@ {:className (if (= list-id :global) "active" "disabled") :href (routes/feed-url :global)} "Global Feed")) - (when (= list-type :articles/by-tag) + (when (= list-type :app.articles/with-tag) (dom/li :.nav-item (dom/div :.nav-link.active "Tagged with `" list-id "`"))))))) (def ui-feed-selector (prim/factory FeedSelector)) -(defsc FeedScreen [this {:keys [feed-id current-page] tags :tags/all}] - {:ident [:screen/feed :feed-id] +(defsc FeedScreen [this {:keys [feed-id article-list] tags :tags/all}] + {:ident [:screen/feed :feed-id] :initial-state (fn [params] {:screen :screen/feed :feed-id :global - :current-page (prim/get-initial-state pagination/Page - #:pagination{:list-type :articles/by-feed - :list-id :global})}) + :article-list (prim/get-initial-state pagination/List + #:app.articles.list{:list-type :app.articles/on-feed + :list-id :global})}) :query [:screen :feed-id - {:current-page (prim/get-query pagination/Page)} + {:article-list (prim/get-query pagination/List)} {[:tags/all '_] (prim/get-query Tag)}]} (dom/div :.home-page (ui-banner) (dom/div :.container.page (dom/div :.row (dom/div :.col-md-9 - (ui-feed-selector (prim/computed {} {:current-page current-page})) - (pagination/ui-page (prim/computed current-page {:load-page #(prim/transact! this `[(load-feed ~%)])}))) + (ui-feed-selector article-list) + (pagination/ui-list article-list)) (ui-tags tags))))) -(defsc TagScreen [this {:keys [tag current-page] tags :tags/all}] - {:ident [:screen/feed :tag] +(defsc TagScreen [this {:keys [tag article-list] tags :tags/all}] + {:ident [:screen/tag :tag] :initial-state (fn [params] {:screen :screen/tag - :tag "fulcro" - :current-page (prim/get-initial-state pagination/Page - #:pagination{:list-type :articles/by-tag - :list-id "fulcro"})}) + :tag "fulcro" + :article-list (prim/get-initial-state pagination/List + #:app.articles.list{:list-type :app.articles/with-tag + :list-id "fulcro"})}) :query [:screen :tag - {:current-page (prim/get-query pagination/Page)} + {:article-list (prim/get-query pagination/List)} {[:tags/all '_] (prim/get-query Tag)}]} (dom/div :.home-page (ui-banner) (dom/div :.container.page (dom/div :.row (dom/div :.col-md-9 - (ui-feed-selector (prim/computed {} {:current-page current-page})) - (pagination/ui-page (prim/computed current-page {:load-page #(prim/transact! this `[(load-tag ~%)])}))) + (ui-feed-selector article-list) + (pagination/ui-list article-list)) (ui-tags tags))))) ;; mutations -(defmutation load-feed [{:pagination/keys [list-id] :as page}] +(defmutation load-list [{:app.articles.list/keys [list-type list-id] :as article-list}] (action [{:keys [state] :as env}] - (swap! state - #(update-in % [:screen/feed list-id] - (fn [x] (if x - x - {:screen :screen/feed - :feed-id list-id - :current-page {}})))) - (df/load-action env :paginated-list/articles - pagination/Page {:params page - :target [:screen/feed list-id :current-page]})) + (let [[screen-table screen-id-key] + (case list-type + :app.articles/on-feed + [:screen/feed :feed-id] + + :app.articles/with-tag + [:screen/tag :tag])] + (swap! state + #(update-in % [screen-table list-id] + (fn [x] (if x + x + {:screen screen-table + screen-id-key list-id + :article-list {}})))) + (df/load-action env [:app.articles/list article-list] + pagination/List {:target [screen-table list-id :article-list]}))) (remote [env] (df/remote-load env)) (refresh [env] - [:pagination/list-type :current-page])) - -(defmutation load-tag [{:pagination/keys [list-id] :as page}] - (action [{:keys [state] :as env}] - (swap! state - #(update-in % [:screen/tag list-id] - (fn [x] (if x - x - {:screen :screen/tag - :tag list-id - :current-page {}})))) - (df/load-action env :paginated-list/articles - pagination/Page {:params page - :target [:screen/tag list-id :current-page]})) - (remote [env] - (df/remote-load env)) - (refresh [env] - [:pagination/list-type :current-page])) + [:app.articles.list/list-type :article-list])) diff --git a/src/conduit/ui/pagination.cljs b/src/conduit/ui/pagination.cljs index ab5c50c..7664554 100644 --- a/src/conduit/ui/pagination.cljs +++ b/src/conduit/ui/pagination.cljs @@ -1,62 +1,121 @@ (ns conduit.ui.pagination + (:refer-clojure :exclude [List]) (:require [fulcro.client.primitives :as prim :refer [defsc]] [fulcro.client.dom :as dom] [conduit.ui.article-preview :as preview] + [fulcro.client.mutations :as m :refer [defmutation returning]] [fulcro.client.routing :as r] - [conduit.util :as util])) + [conduit.util :as util :refer [list-ident list-ident-value]])) -(defn page-ident [props] - [:pagination/page - (select-keys props [:pagination/list-type :pagination/list-id :pagination/size - (if (number? (:pagination/end props)) - :pagination/end - :pagination/start)])]) +(defn page-ident-value + [{:app.articles.list.page/keys [start end] :as props}] + (merge (list-ident-value props) + #:app.articles.list.page{:start start :end end})) -(defsc Page [this {:pagination/keys [list-type list-id size start end previous-id next-id items] :as props} - {:keys [load-page]}] +(defn page-ident + [props] + [:app.articles.list/page + (page-ident-value props)]) + +(defn has-previous-page? + [{:app.articles.list/keys [current-page first-item-id] :as article-list}] + (and (not (nil? first-item-id)) + (not= first-item-id (:app.articles.list.page/start current-page)))) + +(defn has-next-page? + [{:app.articles.list/keys [current-page last-item-id] :as article-list}] + (and (not (nil? last-item-id)) + (not= last-item-id (:app.articles.list.page/end current-page)))) + +(defsc Page + [this {:app.articles.list/keys [list-type list-id direction] + :app.articles.list.page/keys [start end items] + :as props} + {:keys [article-list]}] {:ident (fn [] (page-ident props)) :initial-state (fn [params] - (merge #:pagination{:list-type :articles/by-feed - :list-id :global - :size 5 - :start :empty - :previous-id nil - :next-id nil - :items (prim/get-initial-state preview/ArticlePreview {})} + (merge (list-ident-value params) + #:app.articles.list.page{:start :none + :end :none + :items (prim/get-initial-state preview/ArticlePreview {})} params)) - :query [:pagination/list-type :pagination/list-id :pagination/size - :pagination/start :pagination/end - :pagination/next-id :pagination/previous-id - {:pagination/items (prim/get-query preview/ArticlePreview)}]} - (dom/div - (preview/article-list this - (if (number? end) (reverse items) items) - (cond - (and (= list-type :articles/by-feed) (= list-id :personal)) - "You have no article!" - - :default - "No article!")) - (dom/div - (dom/button :.btn.btn-sm - (if previous-id - {:onClick #(load-page previous-id) :className "action-btn btn-outline-primary"} - {:className "btn-outline-secondary"}) - "Previous") - (dom/button :.btn.btn-sm - (if next-id - {:onClick #(load-page next-id) :className "action-btn btn-outline-primary"} - {:className "btn-outline-secondary"}) - "Next")))) + :query [:app.articles.list/list-type + :app.articles.list/list-id + :app.articles.list/direction + :app.articles.list/size + :app.articles.list.page/start + :app.articles.list.page/end + {:app.articles.list.page/items (prim/get-query preview/ArticlePreview)}]} + (preview/article-list this + (if (= :forward direction) items (reverse items)) + (cond + (and (= list-type :app.articles/on-feed) (= list-id :personal)) + "You have no article! Try to follow more people." + + :default + "No article!"))) (def ui-page (prim/factory Page)) +(defsc List + [this {:app.articles.list/keys [list-type list-id direction size current-page] + :as props}] + {:ident (fn [] (list-ident props)) + :initial-state (fn [params] + (merge (list-ident-value params) + #:app.articles.list{:first-item-id nil + :last-item-id nil + :total-items 0 + :streak [] + :current-page (prim/get-initial-state Page params)} + params)) + :query [:app.articles.list/list-type + :app.articles.list/list-id + :app.articles.list/direction + :app.articles.list/size + :app.articles.list/first-item-id + :app.articles.list/last-item-id + :app.articles.list/total-items + {:app.articles.list/current-page (prim/get-query Page)}]} + (if-not current-page + (dom/div "No article") + (dom/div + (ui-page current-page) + (dom/div + (dom/button :.btn.btn-sm + (if (has-previous-page? props) + {:onClick #(prim/ptransact! this `[(previous-page ~(page-ident-value current-page))]) + :className "action-btn btn-outline-primary"} + {:className "btn-outline-secondary"}) + "Previous") + (dom/button :.btn.btn-sm + (if (has-next-page? props) + {:onClick #(prim/ptransact! this `[(next-page ~(page-ident-value current-page))]) + :className "action-btn btn-outline-primary"} + {:className "btn-outline-secondary"}) + "Next"))))) + +(def ui-list (prim/factory List)) + (r/defsc-router PageRouter [this props] {:router-id :router/page :ident (fn [] (page-ident props)) :default-route Page - :router-targets {:pagination/page Page}} + :router-targets {:app.articles.list/page Page}} (dom/div "Bad route!")) (def ui-page-router (prim/factory PageRouter)) + +(defmutation next-page [page-ident] + #_ + (action [{:keys [state] :as env}]) + (remote [{:keys [ast state]}] + (returning ast state List))) + +(defmutation previous-page [page-ident] + #_ + (action [{:keys [state] :as env}]) + (remote [{:keys [ast state]}] + (returning ast state List))) + diff --git a/src/conduit/ui/profile.cljs b/src/conduit/ui/profile.cljs index e4a186f..98d5db3 100644 --- a/src/conduit/ui/profile.cljs +++ b/src/conduit/ui/profile.cljs @@ -18,71 +18,75 @@ :initial-state (fn [params] #:user {:id :guest}) :query [:user/id :user/name :user/username :user/image :user/bio :user/followed-by-me :user/followed-by-count]} - (dom/div :.user-info - (dom/div :.container - (dom/div :.row - (dom/div :.col-xs-12.col-md-10.offset-md-1 - (dom/img :.user-img {:src (or image other/default-user-image)}) - (dom/h4 name) - (dom/p bio) - (let [current-user-id (-> (prim/shared this :user/whoami) :user/id)] - (if (= id current-user-id) - (dom/button :.btn.btn-sm.btn-outline-secondary - "You have " followed-by-count " followers") - (dom/button :.btn.btn-sm.btn-outline-secondary.action-btn - {:onClick #(if (= :guest current-user-id) - (js/alert "You must log in first") - (if followed-by-me - (prim/transact! this `[(mutations/unfollow {:user/id ~id})]) - (prim/transact! this `[(mutations/follow {:user/id ~id})])))} - (dom/i :.ion-plus-round) - (if followed-by-me "Unfollow " "Follow ") - name "(" followed-by-count ")")))))))) + (let [whoami (prim/shared this :user/whoami)] + (dom/div :.user-info + (dom/div :.container + (dom/div :.row + (dom/div :.col-xs-12.col-md-10.offset-md-1 + (dom/img :.user-img {:src (or image other/default-user-image)}) + (dom/h4 name) + (dom/p bio) + (let [current-user-id (-> (prim/shared this :user/whoami) :user/id)] + (if (= id (:user/id whoami)) + (dom/button :.btn.btn-sm.btn-outline-secondary + "You have " followed-by-count " followers") + (dom/button :.btn.btn-sm.btn-outline-secondary.action-btn + {:onClick #(if (= :guest (:user/id whoami)) + (js/alert "You must log in first") + (if followed-by-me + (prim/transact! this `[(mutations/unfollow {:user/id ~id})]) + (prim/transact! this `[(mutations/follow {:user/id ~id})])))} + (dom/i :.ion-plus-round) + (if followed-by-me "Unfollow" "Follow") + name " (" followed-by-count ")"))))))))) (def ui-profile (prim/factory Profile)) -(defsc ListSelector [this props {:keys [current-page current-user-name]}] - {:query []} - (let [{:pagination/keys [list-type list-id]} current-page - whoami (prim/shared this :user/whoami)] +(defsc ListSelector [this props {:keys [article-list current-user-name]}] + (let [{:app.articles.list/keys [list-type list-id]} article-list + whoami (prim/shared this :user/whoami)] (dom/div :.articles-toggle (dom/ul :.nav.nav-pills.outline-active (dom/li :.nav-item (dom/div :.nav-link - {:className (when (= list-type :owned-articles/by-user-id) "active") - :onClick #(prim/transact! this `[(load-page #:pagination{:list-type :owned-articles/by-user-id - :list-id ~list-id - :size 5})])} + {:className (when (= list-type :app.articles/owned-by-user) "active") + :onClick #(prim/transact! this + `[(load-list #:app.articles.list{:list-type :app.articles/owned-by-user + :list-id ~list-id + :direction :forward + :size 5})])} (if (= (:user/id whoami) list-id) "My" (str current-user-name "'s")) " Articles")) (dom/li :.nav-item (dom/div :.nav-link - {:className (when (= list-type :liked-articles/by-user-id) "active") - :onClick #(prim/transact! this `[(load-page #:pagination {:list-type :liked-articles/by-user-id - :list-id ~list-id - :size 5})])} + {:className (when (= list-type :app.articles/liked-by-user) "active") + :onClick #(prim/transact! this + `[(load-list #:app.articles.list {:list-type :app.articles/liked-by-user + :list-id ~list-id + :direction :forward + :size 5})])} "Favorited Articles")))))) (def ui-list-selector (prim/factory ListSelector)) -(defsc ProfileScreen [this {:keys [screen profile-to-view user-id current-page]}] +(defsc ProfileScreen [this {:keys [screen profile-to-view user-id article-list]}] {:ident (fn [] [screen user-id]) - :initial-state (fn [params] {:screen :screen.profile/by-user-id - :user-id :guest - :profile-to-view (prim/get-initial-state Profile #:user{:id :guest})}) + :initial-state (fn [params] {:screen :screen.profile/by-user-id + :user-id :guest + :profile-to-view (prim/get-initial-state Profile #:user{:id :guest})}) :query (fn [] [:screen :user-id - {:current-page (prim/get-query pagination/Page)} + {:article-list (prim/get-query pagination/List)} {:profile-to-view (prim/get-query Profile)}])} (dom/div :.profile-page (ui-profile profile-to-view) (dom/div :.container (dom/div :.row (dom/div :.col-xs-12.col-md-10.offset-md-1 - (ui-list-selector (prim/computed {} {:current-page current-page + (ui-list-selector (prim/computed {} {:article-list article-list :current-user-name (:user/name profile-to-view)})) - (pagination/ui-page (prim/computed current-page {:load-page #(prim/transact! this `[(load-page ~%)])}))))))) + (pagination/ui-list article-list)))))) (defmutation load-profile [{:keys [user-id]}] (action [{:keys [state] :as env}] @@ -92,24 +96,24 @@ x {:screen :screen.profile/by-user-id :user-id user-id - :current-page {} + :article-list {} :profile-to-view [:user/by-id user-id]})))) (df/load-action env [:user/by-id user-id] Profile) - (df/load-action env :paginated-list/articles - pagination/Page {:params #:pagination{:list-type :owned-articles/by-user-id - :list-id user-id - :size 5} - :target [:screen.profile/by-user-id user-id :current-page]})) + (df/load-action env [:app.articles/list + #:app.articles.list {:list-type :app.articles/owned-by-user + :list-id user-id + :direction :forward + :size 5}] + pagination/List {:target [:screen.profile/by-user-id user-id :article-list]})) (remote [env] (df/remote-load env)) (refresh [env] [:screen :profile-to-view])) ;; mutations -(defmutation load-page [{:pagination/keys [list-id] :as page}] +(defmutation load-list [{:app.articles.list/keys [list-type list-id] :as page}] (action [{:keys [state] :as env}] - (df/load-action env :paginated-list/articles - pagination/Page {:params page - :target [:screen.profile/by-user-id list-id :current-page]})) + (df/load-action env [:app.articles/list page] + pagination/List {:target [:screen.profile/by-user-id list-id :article-list]})) (remote [env] (df/remote-load env)) (refresh [env] diff --git a/src/conduit/ui/routes.cljs b/src/conduit/ui/routes.cljs index deb1bed..c9ce6db 100644 --- a/src/conduit/ui/routes.cljs +++ b/src/conduit/ui/routes.cljs @@ -57,13 +57,15 @@ :screen.profile/by-user-id `[(conduit.ui.profile/load-profile ~route-params)] :screen/feed - `[(conduit.ui.home/load-feed #:pagination{:list-type :articles/by-feed - :list-id ~(:feed-id route-params) - :size 5})] + `[(conduit.ui.home/load-list #:app.articles.list{:list-type :app.articles/on-feed + :list-id ~(:feed-id route-params) + :direction :forward + :size 5})] :screen/tag - `[(conduit.ui.home/load-tag #:pagination{:list-type :articles/by-tag - :list-id ~(:tag route-params) - :size 5})] + `[(conduit.ui.home/load-list #:app.articles.list{:list-type :app.articles/with-tag + :list-id ~(:tag route-params) + :direction :forward + :size 5})] :screen/editor `[(conduit.ui.editor/load-article-to-editor ~route-params) (conduit.ui.editor/use-article-as-form ~route-params)] diff --git a/src/conduit/util.cljc b/src/conduit/util.cljc index 415a4e8..e9b969f 100644 --- a/src/conduit/util.cljc +++ b/src/conduit/util.cljc @@ -27,3 +27,18 @@ (if (zero? (rem total items-per-page)) 0 1)))) + +(defn list-ident-value + [{:app.articles.list/keys [list-type list-id direction size] + :or {list-type :app.articles/on-feed + list-id :global + direction :forward + size 5}}] + #:app.articles.list{:list-type list-type + :list-id list-id + :direction direction + :size size}) + +(defn list-ident + [props] + [:app.articles/list (list-ident-value props)])