mirror of
https://github.com/penpot/penpot.git
synced 2026-02-12 22:53:02 +00:00
Refactor messages (split ui and business logic).
This commit is contained in:
@@ -15,9 +15,9 @@
|
||||
[uxbox.state :as st]
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.locales :refer (tr)]
|
||||
[uxbox.data.projects :as dp]
|
||||
[uxbox.data.projects :as udp]
|
||||
[uxbox.data.users :as udu]
|
||||
[uxbox.ui.messages :as uum]))
|
||||
[uxbox.data.messages :as udm]))
|
||||
|
||||
;; --- Logged In
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
[uxbox.rstore :as rs]
|
||||
[uxbox.state :as st]
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.locales :refer (tr)]
|
||||
[uxbox.ui.messages :as uum]))
|
||||
[uxbox.locales :refer (tr)]))
|
||||
|
||||
;; --- Assign Errors
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
[uxbox.data.pages :as udp]
|
||||
[uxbox.state :as st]
|
||||
[uxbox.state.project :as stpr]
|
||||
[uxbox.ui.messages :as uum]
|
||||
[uxbox.util.datetime :as dt]
|
||||
[uxbox.util.data :refer (without-keys
|
||||
replace-by-id
|
||||
|
||||
112
src/uxbox/data/messages.cljs
Normal file
112
src/uxbox/data/messages.cljs
Normal file
@@ -0,0 +1,112 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.data.messages
|
||||
(:require [cuerdas.core :as str]
|
||||
[promesa.core :as p]
|
||||
[beicon.core :as rx]
|
||||
[lentes.core :as l]
|
||||
[uxbox.rstore :as rs]))
|
||||
|
||||
;; --- Constants
|
||||
|
||||
(def ^:const +animation-timeout+ 600)
|
||||
|
||||
;; --- Message Event
|
||||
|
||||
(declare hide-message)
|
||||
(declare show-message?)
|
||||
|
||||
(defrecord ShowMessage [data]
|
||||
rs/UpdateEvent
|
||||
(-apply-update [_ state]
|
||||
(let [message (assoc data :state :visible)]
|
||||
(assoc state :message message)))
|
||||
|
||||
rs/WatchEvent
|
||||
(-apply-watch [_ state s]
|
||||
(let [stoper (->> (rx/filter show-message? s)
|
||||
(rx/take 1))]
|
||||
(->> (rx/of (hide-message))
|
||||
(rx/delay (:timeout data))
|
||||
(rx/take-until stoper)))))
|
||||
|
||||
(defn show-message
|
||||
[message]
|
||||
(ShowMessage. message))
|
||||
|
||||
(defn show-message?
|
||||
[v]
|
||||
(instance? ShowMessage v))
|
||||
|
||||
(defn show-error
|
||||
[message & {:keys [timeout] :or {timeout 3000}}]
|
||||
(show-message {:content message
|
||||
:type :error
|
||||
:timeout timeout}))
|
||||
|
||||
(defn show-info
|
||||
[message & {:keys [timeout] :or {timeout 3000}}]
|
||||
(show-message {:content message
|
||||
:type :info
|
||||
:timeout timeout}))
|
||||
|
||||
(defn show-dialog
|
||||
[message & {:keys [on-accept on-cancel]}]
|
||||
(show-message {:content message
|
||||
:on-accept on-accept
|
||||
:on-cancel on-cancel
|
||||
:timeout js/Number.MAX_SAFE_INTEGER
|
||||
:type :dialog}))
|
||||
|
||||
;; --- Hide Message
|
||||
|
||||
(defrecord HideMessage [^:mutable canceled?]
|
||||
rs/UpdateEvent
|
||||
(-apply-update [_ state]
|
||||
(update state :message
|
||||
(fn [v]
|
||||
(if (nil? v)
|
||||
(do (set! canceled? true) nil)
|
||||
(assoc v :state :hide)))))
|
||||
|
||||
rs/WatchEvent
|
||||
(-apply-watch [_ state s]
|
||||
(println "HideMessage.-apply-watch" canceled?)
|
||||
(if canceled?
|
||||
(rx/empty)
|
||||
(->> (rx/of #(dissoc state :message))
|
||||
(rx/delay +animation-timeout+)))))
|
||||
|
||||
(defn hide-message
|
||||
[]
|
||||
(HideMessage. false))
|
||||
|
||||
;; --- Direct Call Api
|
||||
|
||||
(defn error!
|
||||
[& args]
|
||||
(rs/emit! (apply show-error args)))
|
||||
|
||||
(defn info!
|
||||
[& args]
|
||||
(rs/emit! (apply show-info args)))
|
||||
|
||||
(defn dialog!
|
||||
[& args]
|
||||
(rs/emit! (apply show-dialog args)))
|
||||
|
||||
(defn close!
|
||||
[]
|
||||
(rs/emit! (hide-message)))
|
||||
|
||||
(defn error
|
||||
[& args]
|
||||
(rx/of (apply show-error args)))
|
||||
|
||||
(defn info
|
||||
[& args]
|
||||
(rx/of (apply show-info args)))
|
||||
@@ -17,7 +17,6 @@
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.state :as st]
|
||||
[uxbox.state.project :as stpr]
|
||||
[uxbox.ui.messages :as uum]
|
||||
[uxbox.util.datetime :as dt]
|
||||
[uxbox.util.data :refer (without-keys replace-by-id)]))
|
||||
|
||||
@@ -76,7 +75,7 @@
|
||||
(-> (sc/validate! data create-page-schema)
|
||||
(map->CreatePage)))
|
||||
|
||||
;; --- Sync Page
|
||||
;; --- Page Synced
|
||||
|
||||
(defrecord PageSynced [page]
|
||||
rs/UpdateEvent
|
||||
@@ -89,6 +88,8 @@
|
||||
[event]
|
||||
(instance? PageSynced event))
|
||||
|
||||
;; --- Sync Page
|
||||
|
||||
(defrecord SyncPage [id]
|
||||
rs/WatchEvent
|
||||
(-apply-watch [this state s]
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
[uxbox.locales :refer (tr)]
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.state.project :as stpr]
|
||||
[uxbox.data.pages :as udp]
|
||||
[uxbox.ui.messages :as uum]))
|
||||
[uxbox.data.pages :as udp]))
|
||||
|
||||
;; --- Projects Fetched
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
[uxbox.state :as st]
|
||||
[uxbox.schema :as sc]
|
||||
[uxbox.locales :refer (tr)]
|
||||
[uxbox.data.forms :as forms]
|
||||
[uxbox.ui.messages :as uum]))
|
||||
[uxbox.data.forms :as udf]
|
||||
[uxbox.data.messages :as udm]))
|
||||
|
||||
;; --- Profile Fetched
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
(ns uxbox.rstore
|
||||
"Reactive storage management architecture helpers."
|
||||
(:require [beicon.core :as rx]
|
||||
[uxbox.locales :refer (tr)]
|
||||
[uxbox.ui.messages :as uum]))
|
||||
[uxbox.locales :refer (tr)]))
|
||||
|
||||
;; An abstraction for implement a simple state
|
||||
;; transition. The `-apply-update` function receives
|
||||
@@ -99,7 +98,7 @@
|
||||
|
||||
:else
|
||||
(do
|
||||
(uum/error (tr "errors.generic"))
|
||||
(uxbox.data.messages/error! (tr "errors.generic"))
|
||||
(println "Unexpected error: " error)
|
||||
(js/console.log (.-stack error))
|
||||
(rx/throw error))))
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
[uxbox.state :as s]
|
||||
[uxbox.rstore :as rs]
|
||||
[uxbox.data.auth :as da]
|
||||
[uxbox.data.messages :as udm]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.ui.icons :as i]
|
||||
[uxbox.ui.messages :as uum]
|
||||
[uxbox.ui.navigation :as nav]
|
||||
[uxbox.ui.mixins :as mx]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Login
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; --- Login
|
||||
|
||||
(defn- login-submit
|
||||
[event local]
|
||||
|
||||
@@ -1,106 +1,35 @@
|
||||
(ns uxbox.ui.messages
|
||||
(:require [sablono.core :as html :refer-macros [html]]
|
||||
[rum.core :as rum]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]
|
||||
[lentes.core :as l]
|
||||
[uxbox.state :as st]
|
||||
[uxbox.data.messages :as udm]
|
||||
[uxbox.ui.icons :as i]
|
||||
[uxbox.ui.mixins :as mx]
|
||||
[uxbox.util.data :refer (classnames)]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
;; --- Constants
|
||||
;; --- Lenses
|
||||
|
||||
(defonce +message+ (atom nil))
|
||||
|
||||
(def ^:const +animation-timeout+ 600)
|
||||
|
||||
;; --- Helpers
|
||||
|
||||
(defn set-timeout!
|
||||
[ms callback]
|
||||
(js/setTimeout callback ms))
|
||||
|
||||
(defn abort-timeout!
|
||||
[v]
|
||||
(when v
|
||||
(js/clearTimeout v)))
|
||||
|
||||
;; --- Public Api
|
||||
|
||||
(defn- clean-prev-msgstate!
|
||||
[message]
|
||||
(let [type (namespace (:type message))]
|
||||
(case type
|
||||
"notification"
|
||||
(do
|
||||
(abort-timeout! (:tsem-main message))
|
||||
(abort-timeout! (:tsem message)))
|
||||
|
||||
"dialog"
|
||||
(abort-timeout! (:tsem message)))))
|
||||
|
||||
(defn error
|
||||
([message] (error message nil))
|
||||
([message {:keys [timeout] :or {timeout 6000}}]
|
||||
(when-let [prev @+message+]
|
||||
(clean-prev-msgstate! prev))
|
||||
(let [timeout' (+ timeout +animation-timeout+)
|
||||
tsem-main (set-timeout! timeout' #(reset! +message+ nil))
|
||||
tsem (set-timeout! timeout #(swap! +message+ assoc :state :hide))]
|
||||
(reset! +message+ {:type :notification/error
|
||||
:state :normal
|
||||
:tsem-main tsem-main
|
||||
:tsem tsem
|
||||
:content message}))))
|
||||
|
||||
(defn info
|
||||
([message] (info message nil))
|
||||
([message {:keys [timeout] :or {timeout 6000}}]
|
||||
(when-let [prev @+message+]
|
||||
(clean-prev-msgstate! prev))
|
||||
(let [timeout' (+ timeout +animation-timeout+)
|
||||
tsem-main (set-timeout! timeout' #(reset! +message+ nil))
|
||||
tsem (set-timeout! timeout #(swap! +message+ assoc :state :hide))]
|
||||
(reset! +message+ {:type :notification/info
|
||||
:state :normal
|
||||
:tsem-main tsem-main
|
||||
:tsem tsem
|
||||
:content message}))))
|
||||
|
||||
(defn dialog
|
||||
[& {:keys [message on-accept on-cancel]
|
||||
:or {on-cancel (constantly nil)}
|
||||
:as opts}]
|
||||
{:pre [(ifn? on-accept)
|
||||
(string? message)]}
|
||||
(when-let [prev @+message+]
|
||||
(clean-prev-msgstate! prev))
|
||||
(reset! +message+ {:type :dialog/simple
|
||||
:state :normal
|
||||
:content message
|
||||
:on-accept on-accept
|
||||
:on-cancel on-cancel}))
|
||||
(defn close
|
||||
[]
|
||||
(when @+message+
|
||||
(let [timeout +animation-timeout+
|
||||
tsem (set-timeout! timeout #(reset! +message+ nil))]
|
||||
(swap! +message+ assoc
|
||||
:state :hide
|
||||
:tsem tsem))))
|
||||
(def ^:const ^:private message-l
|
||||
(-> (l/key :message)
|
||||
(l/focus-atom st/state)))
|
||||
|
||||
;; --- Notification Component
|
||||
|
||||
(defn notification-render
|
||||
[own message]
|
||||
(let [msgtype (name (:type message))
|
||||
classes (classnames :error (= msgtype "error")
|
||||
:info (= msgtype "info")
|
||||
[own {:keys [type] :as message}]
|
||||
(let [classes (classnames :error (= type :error)
|
||||
:info (= type :info)
|
||||
:hide-message (= (:state message) :hide)
|
||||
:quick true)]
|
||||
:quick true)
|
||||
close #(udm/close!)]
|
||||
(html
|
||||
[:div.message {:class classes}
|
||||
[:div.message-body
|
||||
[:span.close i/close]
|
||||
[:span.close {:on-clock close}
|
||||
i/close]
|
||||
[:span (:content message)]]])))
|
||||
|
||||
(def ^:private notification-box
|
||||
@@ -114,21 +43,21 @@
|
||||
(defn dialog-render
|
||||
[own {:keys [on-accept on-cancel] :as message}]
|
||||
(let [classes (classnames :info true
|
||||
:hide-message (= (:state message) :hide))
|
||||
local (:rum/local own)]
|
||||
:hide-message (= (:state message) :hide))]
|
||||
(letfn [(accept [event]
|
||||
(dom/prevent-default event)
|
||||
(close)
|
||||
(on-accept))
|
||||
(on-accept)
|
||||
(p/schedule 0 udm/close!))
|
||||
|
||||
(cancel [event]
|
||||
(dom/prevent-default event)
|
||||
(close)
|
||||
(when on-cancel
|
||||
(on-cancel)))]
|
||||
(on-cancel))
|
||||
(p/schedule 0 udm/close!))]
|
||||
(html
|
||||
[:div.message {:class classes}
|
||||
[:div.message-body
|
||||
[:span.close i/close]
|
||||
[:span.close {:on-click cancel} i/close]
|
||||
[:span (:content message)]
|
||||
[:div.message-action
|
||||
[:a.btn-transparent.btn-small
|
||||
@@ -148,11 +77,11 @@
|
||||
|
||||
(defn messages-render
|
||||
[own]
|
||||
(when-let [message (rum/react +message+)]
|
||||
(case (namespace (:type message))
|
||||
"notification" (notification-box message)
|
||||
"dialog" (dialog-box message)
|
||||
(throw (ex-info "Invalid message type" message)))))
|
||||
(let [message (rum/react message-l)]
|
||||
(case (:type message)
|
||||
:error (notification-box message)
|
||||
:dialog (dialog-box message)
|
||||
nil)))
|
||||
|
||||
(def ^:const messages
|
||||
(mx/component
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
[uxbox.data.workspace :as dw]
|
||||
[uxbox.data.pages :as udp]
|
||||
[uxbox.data.history :as udh]
|
||||
[uxbox.data.messages :as udm]
|
||||
[uxbox.ui.workspace.base :as wb]
|
||||
[uxbox.ui.messages :as msg]
|
||||
[uxbox.ui.icons :as i]
|
||||
[uxbox.ui.mixins :as mx]
|
||||
[uxbox.util.datetime :as dt]
|
||||
@@ -94,11 +94,11 @@
|
||||
(let [[page history] (:rum/props own)]
|
||||
(if-let [version (:selected history)]
|
||||
(let [selected (get-in history [:by-version version])]
|
||||
(msg/dialog
|
||||
:message (tr "history.alert-message" version)
|
||||
(udm/dialog!
|
||||
(tr "history.alert-message" version)
|
||||
:on-accept #(rs/emit! (udh/apply-selected-history (:id page)))
|
||||
:on-cancel #(rs/emit! (udh/discard-selected-history (:id page)))))
|
||||
(msg/close))
|
||||
(udm/close!))
|
||||
own))
|
||||
|
||||
(def history-list
|
||||
|
||||
Reference in New Issue
Block a user