mirror of
https://github.com/penpot/penpot.git
synced 2025-01-08 16:00:19 -05:00
♻️ Refactor auth related components
This commit is contained in:
parent
c598656f60
commit
3f2cd30f52
6 changed files with 267 additions and 222 deletions
|
@ -92,7 +92,7 @@
|
||||||
(assoc :message (tr "errors.email-invalid"))))))
|
(assoc :message (tr "errors.email-invalid"))))))
|
||||||
|
|
||||||
(mf/defc login-form
|
(mf/defc login-form
|
||||||
[{:keys [params on-success-callback] :as props}]
|
[{:keys [params on-success] :as props}]
|
||||||
(let [initial (mf/use-memo (mf/deps params) (constantly params))
|
(let [initial (mf/use-memo (mf/deps params) (constantly params))
|
||||||
|
|
||||||
totp* (mf/use-state false)
|
totp* (mf/use-state false)
|
||||||
|
@ -104,64 +104,74 @@
|
||||||
:initial initial)
|
:initial initial)
|
||||||
|
|
||||||
on-error
|
on-error
|
||||||
(fn [cause]
|
(mf/use-fn
|
||||||
(when (map? cause)
|
(fn [form cause]
|
||||||
(err/print-trace! cause)
|
(when (map? cause)
|
||||||
(err/print-data! cause)
|
(err/print-trace! cause)
|
||||||
(err/print-explain! cause))
|
(err/print-data! cause)
|
||||||
|
(err/print-explain! cause))
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(and (= :totp (:code cause))
|
|
||||||
(= :negotiation (:type cause)))
|
(and (= :totp (:code cause))
|
||||||
(do
|
(= :negotiation (:type cause)))
|
||||||
(reset! totp* true)
|
(reset! totp* true)
|
||||||
(reset! error (tr "errors.missing-totp"))
|
|
||||||
(swap! form (fn [form]
|
(and (= :invalid-totp (:code cause))
|
||||||
(-> form
|
(= :negotiation (:type cause)))
|
||||||
(update :errors assoc :totp {:message (tr "errors.missing-totp")})
|
(do
|
||||||
(update :touched assoc :totp true)))))
|
;; (reset! error (tr "errors.invalid-totp"))
|
||||||
|
(swap! form (fn [form]
|
||||||
|
(-> form
|
||||||
|
(update :errors assoc :totp {:message (tr "errors.invalid-totp")})
|
||||||
|
(update :touched assoc :totp true)))))
|
||||||
|
|
||||||
|
|
||||||
(and (= :restriction (:type cause))
|
(and (= :restriction (:type cause))
|
||||||
(= :passkey-disabled (:code cause)))
|
(= :passkey-disabled (:code cause)))
|
||||||
(reset! error (tr "errors.wrong-credentials"))
|
(reset! error (tr "errors.wrong-credentials"))
|
||||||
|
|
||||||
(and (= :restriction (:type cause))
|
(and (= :restriction (:type cause))
|
||||||
(= :profile-blocked (:code cause)))
|
(= :profile-blocked (:code cause)))
|
||||||
(reset! error (tr "errors.profile-blocked"))
|
(reset! error (tr "errors.profile-blocked"))
|
||||||
|
|
||||||
(and (= :restriction (:type cause))
|
(and (= :restriction (:type cause))
|
||||||
(= :admin-only-profile (:code cause)))
|
(= :admin-only-profile (:code cause)))
|
||||||
(reset! error (tr "errors.profile-blocked"))
|
(reset! error (tr "errors.profile-blocked"))
|
||||||
|
|
||||||
(and (= :validation (:type cause))
|
(and (= :validation (:type cause))
|
||||||
(= :wrong-credentials (:code cause)))
|
(= :wrong-credentials (:code cause)))
|
||||||
(reset! error (tr "errors.wrong-credentials"))
|
(reset! error (tr "errors.wrong-credentials"))
|
||||||
|
|
||||||
(and (= :validation (:type cause))
|
(and (= :validation (:type cause))
|
||||||
(= :account-without-password (:code cause)))
|
(= :account-without-password (:code cause)))
|
||||||
(reset! error (tr "errors.wrong-credentials"))
|
(reset! error (tr "errors.wrong-credentials"))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(reset! error (tr "errors.generic"))))
|
(reset! error (tr "errors.generic")))))
|
||||||
|
|
||||||
on-success-default
|
on-success-default
|
||||||
(fn [data]
|
(mf/use-fn
|
||||||
(when-let [token (:invitation-token data)]
|
(fn [data]
|
||||||
(st/emit! (rt/nav :auth-verify-token {} {:token token}))))
|
(when-let [token (:invitation-token data)]
|
||||||
|
(st/emit! (rt/nav :auth-verify-token {} {:token token})))))
|
||||||
|
|
||||||
on-success
|
on-success
|
||||||
(fn [data]
|
(mf/use-fn
|
||||||
(if (nil? on-success-callback)
|
(mf/deps on-success)
|
||||||
(on-success-default data)
|
(fn [data]
|
||||||
(on-success-callback)))
|
(if (fn? on-success)
|
||||||
|
(on-success data)
|
||||||
|
(on-success-default data))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [form event]
|
(fn [form event]
|
||||||
(let [event (dom/event->native-event event)
|
(let [event (dom/event->native-event event)
|
||||||
submitter (unchecked-get event "submitter")
|
submitter (unchecked-get event "submitter")
|
||||||
submitter (dom/get-data submitter "role")]
|
submitter (dom/get-data submitter "role")
|
||||||
|
on-error (partial on-error form)
|
||||||
|
on-success (partial on-success form)]
|
||||||
|
|
||||||
(case submitter
|
(case submitter
|
||||||
"login-with-passkey"
|
"login-with-passkey"
|
||||||
|
@ -175,6 +185,7 @@
|
||||||
{:on-error on-error
|
{:on-error on-error
|
||||||
:on-success on-success})]
|
:on-success on-success})]
|
||||||
(st/emit! (du/login-with-password params)))
|
(st/emit! (du/login-with-password params)))
|
||||||
|
|
||||||
nil))))
|
nil))))
|
||||||
|
|
||||||
on-submit-ldap
|
on-submit-ldap
|
||||||
|
@ -284,7 +295,7 @@
|
||||||
(tr "auth.login-with-oidc-submit")]]))
|
(tr "auth.login-with-oidc-submit")]]))
|
||||||
|
|
||||||
(mf/defc login-methods
|
(mf/defc login-methods
|
||||||
[{:keys [params on-success-callback] :as props}]
|
[{:keys [params on-success] :as props}]
|
||||||
[:*
|
[:*
|
||||||
(when show-alt-login-buttons?
|
(when show-alt-login-buttons?
|
||||||
[:*
|
[:*
|
||||||
|
@ -306,35 +317,40 @@
|
||||||
(when (or (contains? cf/flags :login)
|
(when (or (contains? cf/flags :login)
|
||||||
(contains? cf/flags :login-with-password)
|
(contains? cf/flags :login-with-password)
|
||||||
(contains? cf/flags :login-with-ldap))
|
(contains? cf/flags :login-with-ldap))
|
||||||
[:& login-form {:params params :on-success-callback on-success-callback}])])
|
[:& login-form {:params params :on-success on-success}])])
|
||||||
|
|
||||||
(mf/defc login-page
|
(mf/defc login-page
|
||||||
[{:keys [params] :as props}]
|
{::mf/wrap-props false}
|
||||||
[:div.generic-form.login-form
|
[{:keys [params]}]
|
||||||
[:div.form-container
|
(let [nav-to-recovery (mf/use-fn #(st/emit! (rt/nav :auth-recovery-request)))
|
||||||
[:h1 {:data-test "login-title"} (tr "auth.login-title")]
|
nav-to-register (mf/use-fn (mf/deps params) #(st/emit! (rt/nav :auth-register {} params)))
|
||||||
|
create-demo (mf/use-fn #(st/emit! (du/create-demo-profile)))]
|
||||||
|
|
||||||
[:& login-methods {:params params}]
|
[:div.generic-form.login-form
|
||||||
|
[:div.form-container
|
||||||
|
[:h1 {:data-test "login-title"} (tr "auth.login-title")]
|
||||||
|
|
||||||
[:div.links
|
[:& login-methods {:params params}]
|
||||||
(when (or (contains? cf/flags :login)
|
|
||||||
(contains? cf/flags :login-with-password))
|
|
||||||
[:div.link-entry
|
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
|
|
||||||
:data-test "forgot-password"}
|
|
||||||
(tr "auth.forgot-password")]])
|
|
||||||
|
|
||||||
(when (contains? cf/flags :registration)
|
[:div.links
|
||||||
[:div.link-entry
|
(when (or (contains? cf/flags :login)
|
||||||
[:span (tr "auth.register") " "]
|
(contains? cf/flags :login-with-password))
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
|
[:div.link-entry
|
||||||
:data-test "register-submit"}
|
[:& lk/link {:on-click nav-to-recovery
|
||||||
(tr "auth.register-submit")]])]
|
:data-test "forgot-password"}
|
||||||
|
(tr "auth.forgot-password")]])
|
||||||
|
|
||||||
(when (contains? cf/flags :demo-users)
|
(when (contains? cf/flags :registration)
|
||||||
[:div.links.demo
|
[:div.link-entry
|
||||||
[:div.link-entry
|
[:span (tr "auth.register") " "]
|
||||||
[:span (tr "auth.create-demo-profile") " "]
|
[:& lk/link {:on-click nav-to-register
|
||||||
[:& lk/link {:action #(st/emit! (du/create-demo-profile))
|
:data-test "register-submit"}
|
||||||
:data-test "demo-account-link"}
|
(tr "auth.register-submit")]])]
|
||||||
(tr "auth.create-demo-account")]]])]])
|
|
||||||
|
(when (contains? cf/flags :demo-users)
|
||||||
|
[:div.links.demo
|
||||||
|
[:div.link-entry
|
||||||
|
[:span (tr "auth.create-demo-profile") " "]
|
||||||
|
[:& lk/link {:on-click create-demo
|
||||||
|
:data-test "demo-account-link"}
|
||||||
|
(tr "auth.create-demo-account")]]])]]))
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(s/def ::email ::us/email)
|
(s/def ::email ::us/email)
|
||||||
(s/def ::recovery-request-form (s/keys :req-un [::email]))
|
(s/def ::recovery-request-form
|
||||||
|
(s/keys :req-un [::email]))
|
||||||
|
|
||||||
(defn handle-error-messages
|
(defn handle-error-messages
|
||||||
[errors _data]
|
[errors _data]
|
||||||
(d/update-when errors :email
|
(d/update-when errors :email
|
||||||
|
@ -31,24 +33,27 @@
|
||||||
(assoc :message (tr "errors.email-invalid"))))))
|
(assoc :message (tr "errors.email-invalid"))))))
|
||||||
|
|
||||||
(mf/defc recovery-form
|
(mf/defc recovery-form
|
||||||
[{:keys [on-success-callback] :as props}]
|
{::mf/wrap-props false}
|
||||||
|
[{:keys [on-success]}]
|
||||||
(let [form (fm/use-form :spec ::recovery-request-form
|
(let [form (fm/use-form :spec ::recovery-request-form
|
||||||
:validators [handle-error-messages]
|
:validators [handle-error-messages]
|
||||||
:initial {})
|
:initial {})
|
||||||
submitted (mf/use-state false)
|
submitted (mf/use-state false)
|
||||||
|
|
||||||
default-success-finish #(st/emit! (dm/info (tr "auth.notifications.recovery-token-sent")))
|
default-on-success
|
||||||
|
(mf/use-fn #(st/emit! (dm/info (tr "auth.notifications.recovery-token-sent"))))
|
||||||
|
|
||||||
on-success
|
on-success
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
|
(mf/deps default-on-success on-success)
|
||||||
(fn [cdata _]
|
(fn [cdata _]
|
||||||
(reset! submitted false)
|
(reset! submitted false)
|
||||||
(if (nil? on-success-callback)
|
(if (fn? on-success)
|
||||||
(default-success-finish)
|
(on-success (:email cdata))
|
||||||
(on-success-callback (:email cdata)))))
|
(default-on-success))))
|
||||||
|
|
||||||
on-error
|
on-error
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [data {:keys [code] :as error}]
|
(fn [data {:keys [code] :as error}]
|
||||||
(reset! submitted false)
|
(reset! submitted false)
|
||||||
(case code
|
(case code
|
||||||
|
@ -64,7 +69,7 @@
|
||||||
(rx/throw error))))
|
(rx/throw error))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn []
|
(fn []
|
||||||
(reset! submitted true)
|
(reset! submitted true)
|
||||||
(let [cdata (:clean-data @form)
|
(let [cdata (:clean-data @form)
|
||||||
|
@ -74,32 +79,34 @@
|
||||||
(reset! form nil)
|
(reset! form nil)
|
||||||
(st/emit! (du/request-profile-recovery params)))))]
|
(st/emit! (du/request-profile-recovery params)))))]
|
||||||
|
|
||||||
[:& fm/form {:on-submit on-submit
|
[:& fm/form {:on-submit on-submit :form form}
|
||||||
:form form}
|
|
||||||
[:div.fields-row
|
[:div.fields-row
|
||||||
[:& fm/input {:name :email
|
[:& fm/input
|
||||||
:label (tr "auth.email")
|
{:name :email
|
||||||
:help-icon i/at
|
:label (tr "auth.email")
|
||||||
:type "text"}]]
|
:help-icon i/at
|
||||||
|
:type "text"}]]
|
||||||
|
|
||||||
[:> fm/submit-button*
|
[:> fm/submit-button*
|
||||||
{:label (tr "auth.recovery-request-submit")
|
{:label (tr "auth.recovery-request-submit")
|
||||||
:data-test "recovery-resquest-submit"}]]))
|
:data-test "recovery-resquest-submit"}]]))
|
||||||
|
|
||||||
|
|
||||||
;; --- Recovery Request Page
|
;; --- Recovery Request Page
|
||||||
|
|
||||||
(mf/defc recovery-request-page
|
(mf/defc recovery-request-page
|
||||||
[{:keys [params on-success-callback go-back-callback] :as props}]
|
{::mf/wrap-props false}
|
||||||
(let [default-go-back #(st/emit! (rt/nav :auth-login))
|
[{:keys [params on-success on-go-back]}]
|
||||||
go-back (or go-back-callback default-go-back)]
|
(let [default-go-back (mf/use-fn #(st/emit! (rt/nav :auth-login)))
|
||||||
|
on-go-back (or on-go-back default-go-back)]
|
||||||
[:section.generic-form
|
[:section.generic-form
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:h1 (tr "auth.recovery-request-title")]
|
[:h1 (tr "auth.recovery-request-title")]
|
||||||
[:div.subtitle (tr "auth.recovery-request-subtitle")]
|
[:div.subtitle (tr "auth.recovery-request-subtitle")]
|
||||||
[:& recovery-form {:params params :on-success-callback on-success-callback}]
|
[:& recovery-form
|
||||||
|
{:params params
|
||||||
|
:on-success on-success}]
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:& lk/link {:action go-back
|
[:& lk/link {:on-click on-go-back
|
||||||
:data-test "go-back-link"}
|
:data-test "go-back-link"}
|
||||||
(tr "labels.go-back")]]]]]))
|
(tr "labels.go-back")]]]]]))
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[app.main.ui.auth.login :as login]
|
[app.main.ui.auth.login :as login]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
[app.main.ui.components.link :as lk]
|
[app.main.ui.components.link :as lk]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.messages :as msgs]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
|
@ -55,63 +56,64 @@
|
||||||
(s/keys :req-un [::password ::email]
|
(s/keys :req-un [::password ::email]
|
||||||
:opt-un [::invitation-token]))
|
:opt-un [::invitation-token]))
|
||||||
|
|
||||||
(defn- handle-prepare-register-error
|
|
||||||
[form {:keys [type code] :as cause}]
|
|
||||||
(condp = [type code]
|
|
||||||
[:restriction :registration-disabled]
|
|
||||||
(st/emit! (dm/error (tr "errors.registration-disabled")))
|
|
||||||
|
|
||||||
[:restriction :profile-blocked]
|
|
||||||
(st/emit! (dm/error (tr "errors.profile-blocked")))
|
|
||||||
|
|
||||||
[:validation :email-has-permanent-bounces]
|
|
||||||
(let [email (get @form [:data :email])]
|
|
||||||
(st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email))))
|
|
||||||
|
|
||||||
[:validation :email-already-exists]
|
|
||||||
(swap! form assoc-in [:errors :email]
|
|
||||||
{:message "errors.email-already-exists"})
|
|
||||||
|
|
||||||
[:validation :email-as-password]
|
|
||||||
(swap! form assoc-in [:errors :password]
|
|
||||||
{:message "errors.email-as-password"})
|
|
||||||
|
|
||||||
(st/emit! (dm/error (tr "errors.generic")))))
|
|
||||||
|
|
||||||
(defn- handle-prepare-register-success
|
|
||||||
[params]
|
|
||||||
(st/emit! (rt/nav :auth-register-validate {} params)))
|
|
||||||
|
|
||||||
|
|
||||||
(mf/defc register-form
|
(mf/defc register-form
|
||||||
[{:keys [params on-success-callback] :as props}]
|
[{:keys [params on-success]}]
|
||||||
(let [initial (mf/use-memo (mf/deps params) (constantly params))
|
(let [initial (hooks/use-equal-memo params)
|
||||||
form (fm/use-form :spec ::register-form
|
form (fm/use-form :spec ::register-form
|
||||||
:validators [validate
|
:validators [validate
|
||||||
(fm/validate-not-empty :password (tr "auth.password-not-empty"))]
|
(fm/validate-not-empty :password (tr "auth.password-not-empty"))]
|
||||||
:initial initial)
|
:initial initial)
|
||||||
submitted? (mf/use-state false)
|
submitted? (mf/use-state false)
|
||||||
|
|
||||||
on-success (fn [p]
|
on-success-default
|
||||||
(if (nil? on-success-callback)
|
(mf/use-fn #(st/emit! (rt/nav :auth-register-validate {} %)))
|
||||||
(handle-prepare-register-success p)
|
|
||||||
(on-success-callback p)))
|
on-success
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps on-success on-success-default)
|
||||||
|
(fn [_ data]
|
||||||
|
(if (fn? on-success)
|
||||||
|
(on-success data)
|
||||||
|
(on-success-default data))))
|
||||||
|
|
||||||
|
on-error
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [form {:keys [type code] :as cause}]
|
||||||
|
(condp = [type code]
|
||||||
|
[:restriction :registration-disabled]
|
||||||
|
(st/emit! (dm/error (tr "errors.registration-disabled")))
|
||||||
|
|
||||||
|
[:restriction :profile-blocked]
|
||||||
|
(st/emit! (dm/error (tr "errors.profile-blocked")))
|
||||||
|
|
||||||
|
[:validation :email-has-permanent-bounces]
|
||||||
|
(let [email (get @form [:data :email])]
|
||||||
|
(st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email))))
|
||||||
|
|
||||||
|
[:validation :email-already-exists]
|
||||||
|
(swap! form assoc-in [:errors :email]
|
||||||
|
{:message "errors.email-already-exists"})
|
||||||
|
|
||||||
|
[:validation :email-as-password]
|
||||||
|
(swap! form assoc-in [:errors :password]
|
||||||
|
{:message "errors.email-as-password"})
|
||||||
|
|
||||||
|
(st/emit! (dm/error (tr "errors.generic"))))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
|
(mf/deps on-success on-error)
|
||||||
(fn [form _event]
|
(fn [form _event]
|
||||||
(reset! submitted? true)
|
(reset! submitted? true)
|
||||||
(let [cdata (:clean-data @form)]
|
(let [cdata (:clean-data @form)
|
||||||
|
on-error (partial on-error form)
|
||||||
|
on-success (partial on-success form)]
|
||||||
(->> (rp/cmd! :prepare-register-profile cdata)
|
(->> (rp/cmd! :prepare-register-profile cdata)
|
||||||
(rx/map #(merge % params))
|
(rx/map #(merge % params))
|
||||||
(rx/finalize #(reset! submitted? false))
|
(rx/finalize #(reset! submitted? false))
|
||||||
(rx/subs
|
(rx/subs on-success on-error)))))]
|
||||||
on-success
|
|
||||||
(partial handle-prepare-register-error form))))))]
|
|
||||||
|
|
||||||
|
[:& fm/form {:on-submit on-submit :form form}
|
||||||
[:& fm/form {:on-submit on-submit
|
|
||||||
:form form}
|
|
||||||
[:div.fields-row
|
[:div.fields-row
|
||||||
[:& fm/input {:type "email"
|
[:& fm/input {:type "email"
|
||||||
:name :email
|
:name :email
|
||||||
|
@ -131,7 +133,7 @@
|
||||||
|
|
||||||
|
|
||||||
(mf/defc register-methods
|
(mf/defc register-methods
|
||||||
[{:keys [params on-success-callback] :as props}]
|
[{:keys [params on-success]}]
|
||||||
[:*
|
[:*
|
||||||
(when login/show-alt-login-buttons?
|
(when login/show-alt-login-buttons?
|
||||||
[:*
|
[:*
|
||||||
|
@ -149,62 +151,39 @@
|
||||||
[:span.text (tr "labels.or")]
|
[:span.text (tr "labels.or")]
|
||||||
[:span.line]])])
|
[:span.line]])])
|
||||||
|
|
||||||
[:& register-form {:params params :on-success-callback on-success-callback}]])
|
[:& register-form {:params params :on-success on-success}]])
|
||||||
|
|
||||||
(mf/defc register-page
|
(mf/defc register-page
|
||||||
[{:keys [params] :as props}]
|
[{:keys [params]}]
|
||||||
[:div.form-container
|
(let [nav-to-login (mf/use-fn (mf/deps params) #(st/emit! (rt/nav :auth-login {} params)))
|
||||||
|
create-demo (mf/use-fn #(st/emit! (du/create-demo-profile)))]
|
||||||
|
|
||||||
[:h1 {:data-test "registration-title"} (tr "auth.register-title")]
|
[:div.form-container
|
||||||
[:div.subtitle (tr "auth.register-subtitle")]
|
|
||||||
|
|
||||||
(when (contains? cf/flags :demo-warning)
|
[:h1 {:data-test "registration-title"} (tr "auth.register-title")]
|
||||||
[:& demo-warning])
|
[:div.subtitle (tr "auth.register-subtitle")]
|
||||||
|
|
||||||
[:& register-methods {:params params}]
|
(when (contains? cf/flags :demo-warning)
|
||||||
|
[:& demo-warning])
|
||||||
|
|
||||||
[:div.links
|
[:& register-methods {:params params}]
|
||||||
[:div.link-entry
|
|
||||||
[:span (tr "auth.already-have-account") " "]
|
|
||||||
|
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params))
|
[:div.links
|
||||||
:data-test "login-here-link"}
|
|
||||||
(tr "auth.login-here")]]
|
|
||||||
|
|
||||||
(when (contains? cf/flags :demo-users)
|
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:span (tr "auth.create-demo-profile") " "]
|
[:span (tr "auth.already-have-account") " "]
|
||||||
[:& lk/link {:action #(st/emit! (du/create-demo-profile))}
|
|
||||||
(tr "auth.create-demo-account")]])]])
|
[:& lk/link {:on-click nav-to-login
|
||||||
|
:data-test "login-here-link"}
|
||||||
|
(tr "auth.login-here")]]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :demo-users)
|
||||||
|
[:div.link-entry
|
||||||
|
[:span (tr "auth.create-demo-profile") " "]
|
||||||
|
[:& lk/link {:on-click create-demo}
|
||||||
|
(tr "auth.create-demo-account")]])]]))
|
||||||
|
|
||||||
;; --- PAGE: register validation
|
;; --- PAGE: register validation
|
||||||
|
|
||||||
(defn- handle-register-error
|
|
||||||
[form error]
|
|
||||||
(case (:code error)
|
|
||||||
:email-already-exists
|
|
||||||
(swap! form assoc-in [:errors :email]
|
|
||||||
{:message "errors.email-already-exists"})
|
|
||||||
|
|
||||||
(do
|
|
||||||
(println (:explain error))
|
|
||||||
(st/emit! (dm/error (tr "errors.generic"))))))
|
|
||||||
|
|
||||||
(defn- handle-register-success
|
|
||||||
[data]
|
|
||||||
(cond
|
|
||||||
(some? (:invitation-token data))
|
|
||||||
(let [token (:invitation-token data)]
|
|
||||||
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
|
|
||||||
|
|
||||||
;; The :is-active flag is true, when insecure-register is enabled
|
|
||||||
;; or the user used external auth provider.
|
|
||||||
(:is-active data)
|
|
||||||
(st/emit! (du/login-from-register))
|
|
||||||
|
|
||||||
:else
|
|
||||||
(st/emit! (rt/nav :auth-register-success {} {:email (:email data)}))))
|
|
||||||
|
|
||||||
(s/def ::accept-terms-and-privacy (s/and ::us/boolean true?))
|
(s/def ::accept-terms-and-privacy (s/and ::us/boolean true?))
|
||||||
(s/def ::accept-newsletter-subscription ::us/boolean)
|
(s/def ::accept-newsletter-subscription ::us/boolean)
|
||||||
|
|
||||||
|
@ -218,30 +197,63 @@
|
||||||
::accept-newsletter-subscription])))
|
::accept-newsletter-subscription])))
|
||||||
|
|
||||||
(mf/defc register-validate-form
|
(mf/defc register-validate-form
|
||||||
[{:keys [params on-success-callback] :as props}]
|
[{:keys [params on-success]}]
|
||||||
(let [form (fm/use-form :spec ::register-validate-form
|
(let [params (hooks/use-equal-memo params)
|
||||||
|
form (fm/use-form :spec ::register-validate-form
|
||||||
:validators [(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))
|
:validators [(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))
|
||||||
(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))]
|
(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))]
|
||||||
:initial params)
|
:initial params)
|
||||||
submitted? (mf/use-state false)
|
submitted? (mf/use-state false)
|
||||||
|
|
||||||
on-success (fn [p]
|
on-error
|
||||||
(if (nil? on-success-callback)
|
(mf/use-fn
|
||||||
(handle-register-success p)
|
(fn [form error]
|
||||||
(on-success-callback (:email p))))
|
(case (:code error)
|
||||||
|
:email-already-exists
|
||||||
|
(swap! form assoc-in [:errors :email]
|
||||||
|
{:message "errors.email-already-exists"})
|
||||||
|
|
||||||
|
(do
|
||||||
|
(println (:explain error))
|
||||||
|
(st/emit! (dm/error (tr "errors.generic")))))))
|
||||||
|
|
||||||
|
|
||||||
|
on-success-default
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [data]
|
||||||
|
(cond
|
||||||
|
(some? (:invitation-token data))
|
||||||
|
(let [token (:invitation-token data)]
|
||||||
|
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
|
||||||
|
|
||||||
|
;; The :is-active flag is true, when insecure-register is enabled
|
||||||
|
;; or the user used external auth provider.
|
||||||
|
(:is-active data)
|
||||||
|
(st/emit! (du/login-from-register))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(st/emit! (rt/nav :auth-register-success {} {:email (:email data)})))))
|
||||||
|
|
||||||
|
on-success
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps on-success on-success-default)
|
||||||
|
(fn [_ data]
|
||||||
|
(if (fn? on-success)
|
||||||
|
(on-success data)
|
||||||
|
(on-success-default data))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [form _event]
|
(fn [form _event]
|
||||||
(reset! submitted? true)
|
(reset! submitted? true)
|
||||||
(let [params (:clean-data @form)]
|
(let [params (:clean-data @form)
|
||||||
|
on-success (partial on-success form)
|
||||||
|
on-error (partial on-error form)]
|
||||||
(->> (rp/cmd! :register-profile params)
|
(->> (rp/cmd! :register-profile params)
|
||||||
(rx/finalize #(reset! submitted? false))
|
(rx/finalize #(reset! submitted? false))
|
||||||
(rx/subs on-success
|
(rx/subs on-success on-error)))))]
|
||||||
(partial handle-register-error form))))))]
|
|
||||||
|
|
||||||
[:& fm/form {:on-submit on-submit
|
[:& fm/form {:on-submit on-submit :form form}
|
||||||
:form form}
|
|
||||||
[:div.fields-row
|
[:div.fields-row
|
||||||
[:& fm/input {:name :fullname
|
[:& fm/input {:name :fullname
|
||||||
:label (tr "auth.fullname")
|
:label (tr "auth.fullname")
|
||||||
|
@ -265,20 +277,20 @@
|
||||||
|
|
||||||
|
|
||||||
(mf/defc register-validate-page
|
(mf/defc register-validate-page
|
||||||
[{:keys [params] :as props}]
|
[{:keys [params]}]
|
||||||
[:div.form-container
|
(let [nav-to-register (mf/use-fn #(st/emit! (rt/nav :auth-register {} {})))]
|
||||||
[:h1 {:data-test "register-title"} (tr "auth.register-title")]
|
[:div.form-container
|
||||||
[:div.subtitle (tr "auth.register-subtitle")]
|
[:h1 {:data-test "register-title"} (tr "auth.register-title")]
|
||||||
|
[:div.subtitle (tr "auth.register-subtitle")]
|
||||||
|
|
||||||
[:& register-validate-form {:params params}]
|
[:& register-validate-form {:params params}]
|
||||||
|
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))}
|
[:& lk/link {:on-click nav-to-register} (tr "labels.go-back")]]]]))
|
||||||
(tr "labels.go-back")]]]])
|
|
||||||
|
|
||||||
(mf/defc register-success-page
|
(mf/defc register-success-page
|
||||||
[{:keys [params] :as props}]
|
[{:keys [params]}]
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:div.notification-icon i/icon-verify]
|
[:div.notification-icon i/icon-verify]
|
||||||
[:div.notification-text (tr "auth.verification-email-sent")]
|
[:div.notification-text (tr "auth.verification-email-sent")]
|
||||||
|
|
|
@ -9,13 +9,19 @@
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc link [{:keys [action klass data-test keyboard-action children]}]
|
(mf/defc link
|
||||||
(let [keyboard-action (or keyboard-action action)]
|
{::mf/wrap-props false}
|
||||||
[:a {:on-click action
|
[{:keys [on-click class data-test on-key-enter children]}]
|
||||||
:class klass
|
(let [on-key-enter (or on-key-enter on-click)
|
||||||
:on-key-down (fn [event]
|
on-key-down
|
||||||
(when (kbd/enter? event)
|
(mf/use-fn
|
||||||
(keyboard-action event)))
|
(mf/deps on-key-enter)
|
||||||
|
(fn [event]
|
||||||
|
(when (and (kbd/enter? event) (fn? on-key-enter))
|
||||||
|
(on-key-enter event))))]
|
||||||
|
[:a {:on-click on-click
|
||||||
|
:on-key-down on-key-down
|
||||||
|
:class class
|
||||||
:tab-index "0"
|
:tab-index "0"
|
||||||
:data-test data-test}
|
:data-test data-test}
|
||||||
[:* children]]))
|
children]))
|
||||||
|
|
|
@ -629,19 +629,19 @@
|
||||||
[:ul.sidebar-nav.no-overflow
|
[:ul.sidebar-nav.no-overflow
|
||||||
[:li.recent-projects
|
[:li.recent-projects
|
||||||
{:class-name (when projects? "current")}
|
{:class-name (when projects? "current")}
|
||||||
[:& link {:action go-projects
|
[:& link {:on-click go-projects
|
||||||
:keyboard-action go-projects-with-key}
|
:on-key-enter go-projects-with-key}
|
||||||
[:span.element-title (tr "labels.projects")]]]
|
[:span.element-title (tr "labels.projects")]]]
|
||||||
|
|
||||||
[:li {:class-name (when drafts? "current")}
|
[:li {:class-name (when drafts? "current")}
|
||||||
[:& link {:action go-drafts
|
[:& link {:on-click go-drafts
|
||||||
:keyboard-action go-drafts-with-key}
|
:on-key-enter go-drafts-with-key}
|
||||||
[:span.element-title (tr "labels.drafts")]]]
|
[:span.element-title (tr "labels.drafts")]]]
|
||||||
|
|
||||||
|
|
||||||
[:li {:class-name (when libs? "current")}
|
[:li {:class-name (when libs? "current")}
|
||||||
[:& link {:action go-libs
|
[:& link {:on-click go-libs
|
||||||
:keyboard-action go-libs-with-key}
|
:on-key-enter go-libs-with-key}
|
||||||
[:span.element-title (tr "labels.shared-libraries")]]]]]
|
[:span.element-title (tr "labels.shared-libraries")]]]]]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
@ -650,8 +650,8 @@
|
||||||
[:ul.sidebar-nav.no-overflow
|
[:ul.sidebar-nav.no-overflow
|
||||||
[:li {:class-name (when fonts? "current")}
|
[:li {:class-name (when fonts? "current")}
|
||||||
|
|
||||||
[:& link {:action go-fonts
|
[:& link {:on-click go-fonts
|
||||||
:keyboard-action go-fonts-with-key
|
:on-key-enter go-fonts-with-key
|
||||||
:data-test "fonts"}
|
:data-test "fonts"}
|
||||||
[:span.element-title (tr "labels.fonts")]]]]]
|
[:span.element-title (tr "labels.fonts")]]]]]
|
||||||
|
|
||||||
|
|
|
@ -38,17 +38,21 @@
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(st/emit! (modal/hide)))
|
(st/emit! (modal/hide)))
|
||||||
|
|
||||||
success-email-sent
|
success-email-sent
|
||||||
(fn [email]
|
(fn [{:keys [email]}]
|
||||||
(reset! user-email email)
|
(reset! user-email email)
|
||||||
(set-current-section :email-sent))
|
(set-current-section :email-sent))
|
||||||
|
|
||||||
success-login
|
success-login
|
||||||
(fn []
|
(fn [_]
|
||||||
(.reload js/window.location true))
|
(.reload js/window.location true))
|
||||||
|
|
||||||
success-register
|
success-register
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(reset! register-token (:token data))
|
(reset! register-token (:token data))
|
||||||
(set-current-section :register-validate))]
|
(set-current-section :register-validate))]
|
||||||
|
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(swap! storage assoc :redirect-url uri))
|
(swap! storage assoc :redirect-url uri))
|
||||||
|
|
||||||
|
@ -66,7 +70,7 @@
|
||||||
:login
|
:login
|
||||||
[:div.generic-form.login-form
|
[:div.generic-form.login-form
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:& login-methods {:on-success-callback success-login}]
|
[:& login-methods {:on-success success-login}]
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:a {:on-click #(set-current-section :recovery-request)}
|
[:a {:on-click #(set-current-section :recovery-request)}
|
||||||
|
@ -78,7 +82,7 @@
|
||||||
|
|
||||||
:register
|
:register
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:& register-methods {:on-success-callback success-register}]
|
[:& register-methods {:on-success success-register}]
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:span (tr "auth.already-have-account") " "]
|
[:span (tr "auth.already-have-account") " "]
|
||||||
|
@ -88,15 +92,15 @@
|
||||||
:register-validate
|
:register-validate
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:& register-validate-form {:params {:token @register-token}
|
[:& register-validate-form {:params {:token @register-token}
|
||||||
:on-success-callback success-email-sent}]
|
:on-success success-email-sent}]
|
||||||
[:div.links
|
[:div.links
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:a {:on-click #(set-current-section :register)}
|
[:a {:on-click #(set-current-section :register)}
|
||||||
(tr "labels.go-back")]]]]
|
(tr "labels.go-back")]]]]
|
||||||
|
|
||||||
:recovery-request
|
:recovery-request
|
||||||
[:& recovery-request-page {:go-back-callback #(set-current-section :login)
|
[:& recovery-request-page {:on-go-back #(set-current-section :login)
|
||||||
:on-success-callback success-email-sent}]
|
:on-success success-email-sent}]
|
||||||
:email-sent
|
:email-sent
|
||||||
[:div.form-container
|
[:div.form-container
|
||||||
[:& register-success-page {:params {:email @user-email}}]])]
|
[:& register-success-page {:params {:email @user-email}}]])]
|
||||||
|
|
Loading…
Reference in a new issue