add initial lists UI with list/add/delete and some update support
currently doesn't show cards contained in any lists nor allow adding or removing of cards to/from any lists
This commit is contained in:
parent
ab66ca9a0a
commit
a669221ad7
|
@ -25,6 +25,24 @@ html, body {
|
|||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.context
|
||||
{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.absolute.top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.large-font {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div.popover.card-image {
|
||||
max-width: none;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
[]
|
||||
(not (nil? @user-profile)))
|
||||
|
||||
(defn can-modify-data?
|
||||
[]
|
||||
(or (authenticated?)
|
||||
(not (auth-required?))))
|
||||
|
||||
(defn get-username
|
||||
[]
|
||||
(:username @user-profile))
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
[mtgcoll.client.page :as page]
|
||||
[mtgcoll.client.routes.cards :as cards]
|
||||
[mtgcoll.client.routes.collection :as collection]
|
||||
[mtgcoll.client.routes.lists :as lists]
|
||||
[mtgcoll.client.routes.sets :as sets]
|
||||
[mtgcoll.client.routes.stats :as stats]))
|
||||
[mtgcoll.client.routes.stats :as stats]
|
||||
[mtgcoll.client.utils :refer [parse-int]]))
|
||||
|
||||
(defroute "/" [] (page/page [collection/owned-cards-list]))
|
||||
(defroute "/owned" [] (page/page [collection/owned-cards-list]))
|
||||
|
@ -17,6 +19,8 @@
|
|||
(defroute "/sets" [] (page/page [sets/sets-list]))
|
||||
(defroute "/set/:code" [code] (page/page [sets/set-details code]))
|
||||
(defroute "/card/:id" [id] (page/page [cards/card-details id 0]))
|
||||
(defroute "/lists" [] (page/page [lists/lists-list]))
|
||||
(defroute "/list/:id" [id] (page/page [lists/list-details (parse-int id)]))
|
||||
(defroute "/stats" [] (page/page [stats/stats-page]))
|
||||
(defroute "*" [] (page/barebones-page [:div "not found"]))
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
[bs/Nav
|
||||
[bs/NavItem {:href "#/owned" :active (= :owned active-breadcrumb)} "Owned"]
|
||||
[bs/NavItem {:href "#/all" :active (= :all active-breadcrumb)} "All"]
|
||||
[bs/NavItem {:href "#/lists" :active (= :lists active-breadcrumb)} "Lists"]
|
||||
[bs/NavItem {:href "#/sets" :active (= :sets active-breadcrumb)} "Sets"]
|
||||
[bs/NavItem {:href "#/stats" :active (= :stats active-breadcrumb)} "Statistics"]]
|
||||
(if (auth/auth-required?)
|
||||
|
|
162
src/mtgcoll/client/routes/lists.cljs
Normal file
162
src/mtgcoll/client/routes/lists.cljs
Normal file
|
@ -0,0 +1,162 @@
|
|||
(ns mtgcoll.client.routes.lists
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[reagent.core :as r]
|
||||
[views.reagent.client.component :as vc :refer [view-cursor] :refer-macros [defvc]]
|
||||
[webtools.reagent.bootstrap :as bs]
|
||||
[webtools.cljs.ajax :as ajax]
|
||||
[webtools.cljs.utils :refer [->url redirect!]]
|
||||
[mtgcoll.client.auth :as auth]
|
||||
[mtgcoll.client.page :refer [set-active-breadcrumb! set-error!]]
|
||||
[mtgcoll.client.utils :refer [get-field-value]]
|
||||
[mtgcoll.client.components.utils :refer [click-to-edit-textarea markdown confirm-modal]]))
|
||||
|
||||
(defn create-list-form
|
||||
[visibility-atom]
|
||||
(let [values (r/atom nil)
|
||||
error (r/atom nil)
|
||||
on-close (fn []
|
||||
(reset! values nil)
|
||||
(reset! error nil)
|
||||
(reset! visibility-atom false))
|
||||
on-submit (fn []
|
||||
(reset! error nil)
|
||||
(let [{:keys [name requires-qualities? public?]} @values]
|
||||
(if (string/blank? name)
|
||||
(reset! error "List name must be provided.")
|
||||
(ajax/POST (->url "/lists/add")
|
||||
:params {:name name :public? public? :requires-qualities? requires-qualities?}
|
||||
:on-error #(reset! error "Could not create list. Make sure list name is unique.")
|
||||
:on-success (fn [response]
|
||||
(let [new-list-id (:id (clojure.walk/keywordize-keys response))]
|
||||
(redirect! (str "#/list/" new-list-id))))))))
|
||||
on-key-up #(if (= 13 (.-keyCode %))
|
||||
(on-submit))]
|
||||
(fn []
|
||||
[bs/Modal
|
||||
{:show (boolean @visibility-atom)
|
||||
:on-hide #(reset! visibility-atom false)}
|
||||
[bs/Modal.Header [bs/Modal.Title "Create List"]]
|
||||
[bs/Modal.Body
|
||||
(if @error
|
||||
[bs/Alert {:bsStyle "danger"} @error])
|
||||
[bs/Form {:horizontal true}
|
||||
[bs/FormGroup
|
||||
[bs/Col {:class "text-right" :sm 4} [bs/ControlLabel "List Name"]]
|
||||
[bs/Col {:sm 6}
|
||||
[bs/FormControl
|
||||
{:type "text"
|
||||
:default-value (or (:name @values) "")
|
||||
:on-change #(swap! values assoc :name (get-field-value %))
|
||||
:on-key-up on-key-up}]]]
|
||||
[bs/FormGroup
|
||||
[bs/Col {:class "text-right" :sm 4} [bs/ControlLabel "Card Qualities"]]
|
||||
[bs/Col {:sm 6}
|
||||
[bs/Checkbox
|
||||
{:on-change (fn [e]
|
||||
(let [checked? (-> e .-target .-checked)]
|
||||
(swap! values assoc :requires-qualities?
|
||||
(if checked? true false))))}]]]
|
||||
[bs/FormGroup
|
||||
[bs/Col {:class "text-right" :sm 4} [bs/ControlLabel "Public"]]
|
||||
[bs/Col {:sm 6}
|
||||
[bs/Checkbox
|
||||
{:on-change (fn [e]
|
||||
(let [checked? (-> e .-target .-checked)]
|
||||
(swap! values assoc :public?
|
||||
(if checked? true false))))}]]]]]
|
||||
[bs/Modal.Footer
|
||||
[bs/Button {:bsStyle "primary" :on-click on-submit} "OK"]
|
||||
[bs/Button {:on-click on-close} "Cancel"]]])))
|
||||
|
||||
(defvc lists-list
|
||||
[]
|
||||
(let [show-create-form? (r/atom false)]
|
||||
(fn []
|
||||
(let [lists (view-cursor :lists-list (auth/get-username))]
|
||||
(set-active-breadcrumb! :lists)
|
||||
[:div.context
|
||||
(if (auth/can-modify-data?)
|
||||
[:div.absolute.top-right
|
||||
[bs/Button {:on-click #(reset! show-create-form? true)} "Create List"]])
|
||||
[bs/PageHeader "Lists"]
|
||||
[create-list-form show-create-form?]
|
||||
(if (vc/loading? lists)
|
||||
[:div "Loading ..."]
|
||||
(if (empty? @lists)
|
||||
[bs/Alert {:bsStyle "warning"} "No lists found."]
|
||||
[bs/Table
|
||||
{:bordered true :striped true :condensed true :hover true}
|
||||
[:thead
|
||||
[:tr
|
||||
[:th "Name"]
|
||||
[:th "Cards"]]]
|
||||
[:tbody
|
||||
(doall
|
||||
(map
|
||||
(fn [{:keys [id name is_public]}]
|
||||
^{:key id}
|
||||
[:tr
|
||||
(if (and (auth/authenticated?) (not is_public))
|
||||
{:class "warning"})
|
||||
[:td [:a {:href (->url "#/list/" id)} [:div name]]]
|
||||
[:td "--"]])
|
||||
@lists))]]))]))))
|
||||
|
||||
(defn on-update-list-notes!
|
||||
[list-id notes]
|
||||
(ajax/POST (->url "/lists/update-note")
|
||||
:params {:list-id list-id :note notes}
|
||||
:on-error #(set-error! "Server error while updating list notes.")))
|
||||
|
||||
(defn change-list-visibility!
|
||||
[list-id public?]
|
||||
(ajax/POST (->url "/lists/update-visibility")
|
||||
:params {:list-id list-id :public? public?}
|
||||
:on-error #(set-error! "Server error while updating list public/private visibility.")))
|
||||
|
||||
(defn delete-list!
|
||||
[list-id]
|
||||
(ajax/POST (->url "/lists/remove")
|
||||
:params {:list-id list-id}
|
||||
:on-error #(set-error! "Server error while deleting the list.")
|
||||
:on-success #(redirect! "#/lists")))
|
||||
|
||||
(defvc list-details
|
||||
[list-id]
|
||||
(let [show-delete-confirm? (r/atom false)]
|
||||
(fn [list-id]
|
||||
(set-active-breadcrumb! :lists)
|
||||
(let [list (view-cursor :list-info list-id (auth/get-username))]
|
||||
(cond
|
||||
(and (not (vc/loading? list))
|
||||
(nil? @list))
|
||||
[:div "List not found."]
|
||||
|
||||
(vc/loading? list)
|
||||
[:div "Loading ..."]
|
||||
|
||||
:else
|
||||
[:div.context
|
||||
(if (auth/can-modify-data?)
|
||||
[:div.absolute.top-right
|
||||
(if-not (:is_public @list) [:span.large-font [bs/Label {:bsStyle "danger"} "Private"] " "])
|
||||
(if (:require_qualities @list) [:span.large-font [bs/Label {:bsStyle "primary"} "Card Qualities"] " "])
|
||||
[bs/DropdownButton {:title "Actions"}
|
||||
[bs/MenuItem {:on-click #(js/alert "TODO: Copy to Owned")} "Copy to Owned"]
|
||||
[bs/MenuItem {:on-click #(change-list-visibility! list-id (not (:is_public @list)))} (if (:is_public @list) "Make Private" "Make Public")]
|
||||
[bs/MenuItem {:on-click #(reset! show-delete-confirm? true)} "Delete"]]])
|
||||
[bs/PageHeader (:name @list)]
|
||||
(if (auth/can-modify-data?)
|
||||
[click-to-edit-textarea
|
||||
(:notes @list)
|
||||
{:placeholder "List Notes"
|
||||
:rows 10
|
||||
:on-update #(on-update-list-notes! list-id %)
|
||||
:render markdown}]
|
||||
[markdown (:notes @list)])
|
||||
[confirm-modal
|
||||
show-delete-confirm?
|
||||
{:title "Confirm Delete"
|
||||
:body [:p "Are you sure you want to delete the " [:strong (:name @list)] " list? This cannot be undone."]
|
||||
:on-yes #(delete-list! list-id)}]])))))
|
|
@ -63,3 +63,8 @@
|
|||
[n & [number-only?]]
|
||||
(if n
|
||||
(str (if-not number-only? "$") (pprint/cl-format nil "~,2f" n))))
|
||||
|
||||
(defn parse-int
|
||||
[s]
|
||||
(if s
|
||||
(js/parseInt (string/trim s) 10)))
|
||||
|
|
Loading…
Reference in a new issue