♻️ Refactor profile registration flow.

This commit is contained in:
Andrey Antukh 2021-06-15 17:24:00 +02:00 committed by Andrés Moya
parent c82d936e96
commit 9e3ba85b72
30 changed files with 717 additions and 581 deletions

View file

@ -54,6 +54,11 @@
:browser
:webworker))
(defn- parse-flags
[global]
(let [flags (obj/get global "penpotFlags" "")]
(into #{} (map keyword) (str/words flags))))
(defn- parse-version
[global]
(-> (obj/get global "penpotVersion")
@ -78,6 +83,8 @@
(def themes (obj/get global "penpotThemes"))
(def analytics (obj/get global "penpotAnalyticsEnabled" false))
(def flags (delay (parse-flags global)))
(def version (delay (parse-version global)))
(def target (delay (parse-target global)))
(def browser (delay (parse-browser)))

View file

@ -221,6 +221,7 @@
;; --- EVENT: register
;; TODO: remove
(s/def ::invitation-token ::us/not-empty-string)
(s/def ::register

View file

@ -62,6 +62,8 @@
["/login" :auth-login]
(when cfg/registration-enabled
["/register" :auth-register])
(when cfg/registration-enabled
["/register/validate" :auth-register-validate])
(when cfg/registration-enabled
["/register/success" :auth-register-success])
["/recovery/request" :auth-recovery-request]
@ -112,6 +114,7 @@
(case (:name data)
(:auth-login
:auth-register
:auth-register-validate
:auth-register-success
:auth-recovery-request
:auth-recovery)

View file

@ -14,7 +14,7 @@
[app.main.ui.auth.login :refer [login-page]]
[app.main.ui.auth.recovery :refer [recovery-page]]
[app.main.ui.auth.recovery-request :refer [recovery-request-page]]
[app.main.ui.auth.register :refer [register-page register-success-page]]
[app.main.ui.auth.register :refer [register-page register-success-page register-validate-page]]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.forms :as fm]
@ -36,13 +36,16 @@
[:div.auth
[:section.auth-sidebar
[:a.logo {:href "https://penpot.app"} i/logo]
[:a.logo {:href "#/"} i/logo]
[:span.tagline (t locale "auth.sidebar-tagline")]]
[:section.auth-content
(case section
:auth-register
[:& register-page {:locale locale :params params}]
[:& register-page {:params params}]
:auth-register-validate
[:& register-validate-page {:params params}]
:auth-register-success
[:& register-success-page {:params params}]
@ -55,6 +58,7 @@
:auth-recovery
[:& recovery-page {:locale locale :params params}])
[:div.terms-login
[:a {:href "https://penpot.app/terms.html" :target "_blank"} "Terms of service"]
[:span "and"]

View file

@ -23,6 +23,12 @@
[cljs.spec.alpha :as s]
[rumext.alpha :as mf]))
(def show-alt-login-buttons?
(or cfg/google-client-id
cfg/gitlab-client-id
cfg/github-client-id
cfg/oidc-client-id))
(s/def ::email ::us/email)
(s/def ::password ::us/not-empty-string)
@ -103,13 +109,15 @@
:tab-index "3"
:help-icon i/eye
:label (tr "auth.password")}]]
[:& fm/submit-button
{:label (tr "auth.login-submit")}]
(when cfg/login-with-ldap
[:& fm/submit-button
{:label (tr "auth.login-with-ldap-submit")
:on-click on-submit-ldap}])]]))
[:div.buttons-stack
[:& fm/submit-button
{:label (tr "auth.login-submit")}]
(when cfg/login-with-ldap
[:& fm/submit-button
{:label (tr "auth.login-with-ldap-submit")
:on-click on-submit-ldap}])]]]))
(mf/defc login-buttons
[{:keys [params] :as props}]
@ -147,6 +155,13 @@
[:& login-form {:params params}]
(when show-alt-login-buttons?
[:*
[:span.separator (tr "labels.or")]
[:div.buttons
[:& login-buttons {:params params}]]])
[:div.links
[:div.link-entry
[:a {:on-click #(st/emit! (rt/nav :auth-recovery-request))}
@ -158,7 +173,6 @@
[:a {:on-click #(st/emit! (rt/nav :auth-register {} params))}
(tr "auth.register-submit")]])]
[:& login-buttons {:params params}]
(when cfg/allow-demo-users
[:div.links.demo

View file

@ -86,4 +86,4 @@
[:div.links
[:div.link-entry
[:a {:on-click #(st/emit! (rt/nav :auth-login))}
(tr "auth.go-back-to-login")]]]]])
(tr "labels.go-back")]]]]])

View file

@ -7,10 +7,11 @@
(ns app.main.ui.auth.register
(:require
[app.common.spec :as us]
[app.config :as cfg]
[app.config :as cf]
[app.main.data.users :as du]
[app.main.data.messages :as dm]
[app.main.store :as st]
[app.main.repo :as rp]
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
@ -30,6 +31,8 @@
{:type :warning
:content (tr "auth.demo-warning")}])
;; --- PAGE: Register
(defn- validate
[data]
(let [password (:password data)
@ -48,9 +51,29 @@
(s/def ::terms-privacy ::us/boolean)
(s/def ::register-form
(s/keys :req-un [::password ::fullname ::email ::terms-privacy]
(s/keys :req-un [::password ::email]
:opt-un [::invitation-token]))
(defn- handle-prepare-register-error
[form error]
(case (:code error)
:registration-disabled
(st/emit! (dm/error (tr "errors.registration-disabled")))
:email-has-permanent-bounces
(let [email (get @form [:data :email])]
(st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email))))
:email-already-exists
(swap! form assoc-in [:errors :email]
{:message "errors.email-already-exists"})
(st/emit! (dm/error (tr "errors.generic")))))
(defn- handle-prepare-register-success
[form {:keys [token] :as result}]
(st/emit! (rt/nav :auth-register-validate {} {:token token})))
(mf/defc register-form
[{:keys [params] :as props}]
(let [initial (mf/use-memo (mf/deps params) (constantly params))
@ -59,49 +82,20 @@
:initial initial)
submitted? (mf/use-state false)
on-error
(mf/use-callback
(fn [form error]
(reset! submitted? false)
(case (:code error)
:registration-disabled
(rx/of (dm/error (tr "errors.registration-disabled")))
:email-has-permanent-bounces
(let [email (get @form [:data :email])]
(rx/of (dm/error (tr "errors.email-has-permanent-bounces" email))))
:email-already-exists
(swap! form assoc-in [:errors :email]
{:message "errors.email-already-exists"})
(rx/throw error))))
on-success
(mf/use-callback
(fn [form data]
(reset! submitted? false)
(if-let [token (:invitation-token data)]
(st/emit! (rt/nav :auth-verify-token {} {:token token}))
(st/emit! (rt/nav :auth-register-success {} {:email (:email data)})))))
on-submit
(mf/use-callback
(fn [form event]
(reset! submitted? true)
(let [data (with-meta (:clean-data @form)
{:on-error (partial on-error form)
:on-success (partial on-success form)})]
(st/emit! (du/register data)))))]
(let [params (:clean-data @form)]
(->> (rp/mutation :prepare-register-profile params)
(rx/finalize #(reset! submitted? false))
(rx/subs (partial handle-prepare-register-success form)
(partial handle-prepare-register-error form))))))
]
[:& fm/form {:on-submit on-submit
:form form}
[:div.fields-row
[:& fm/input {:name :fullname
:tab-index "1"
:label (tr "auth.fullname")
:type "text"}]]
[:div.fields-row
[:& fm/input {:type "email"
:name :email
@ -115,18 +109,145 @@
:label (tr "auth.password")
:type "password"}]]
[:& fm/submit-button
{:label (tr "auth.register-submit")
:disabled @submitted?}]]))
(mf/defc register-page
[{:keys [params] :as props}]
[:div.form-container
[:h1 (tr "auth.register-title")]
[:div.subtitle (tr "auth.register-subtitle")]
(when cf/demo-warning
[:& demo-warning])
[:& register-form {:params params}]
(when login/show-alt-login-buttons?
[:*
[:span.separator (tr "labels.or")]
[:div.buttons
[:& login/login-buttons {:params params}]]])
[:div.links
[:div.link-entry
[:span (tr "auth.already-have-account") " "]
[:a {:on-click #(st/emit! (rt/nav :auth-login {} params))
:tab-index "4"}
(tr "auth.login-here")]]
(when cf/allow-demo-users
[:div.link-entry
[:span (tr "auth.create-demo-profile") " "]
[:a {:on-click #(st/emit! (du/create-demo-profile))
:tab-index "5"}
(tr "auth.create-demo-account")]])]])
;; --- PAGE: register validation
(defn- handle-register-error
[form error]
(case (:code error)
:registration-disabled
(st/emit! (dm/error (tr "errors.registration-disabled")))
:email-has-permanent-bounces
(let [email (get @form [:data :email])]
(st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email))))
: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
[form data]
(cond
(some? (:invitation-token data))
(let [token (:invitation-token data)]
(st/emit! (rt/nav :auth-verify-token {} {:token token})))
(not= "penpot" (:auth-backend data))
(st/emit!
(du/fetch-profile)
(rt/nav :dashboard-projects {:team-id (:default-team-id data)}))
:else
(st/emit! (rt/nav :auth-register-success {} {:email (:email data)}))))
(s/def ::accept-terms-and-privacy ::us/boolean)
(s/def ::accept-newsletter-subscription ::us/boolean)
(s/def ::register-validate-form
(s/keys :req-un [::token ::fullname ::accept-terms-and-privacy]
:opt-un [::accept-newsletter-subscription]))
(mf/defc register-validate-form
[{:keys [params] :as props}]
(let [initial (mf/use-memo
(mf/deps params)
(fn []
(assoc params :accept-newsletter-subscription false)))
form (fm/use-form :spec ::register-validate-form
:initial initial)
submitted? (mf/use-state false)
on-submit
(mf/use-callback
(fn [form event]
(reset! submitted? true)
(let [params (:clean-data @form)]
(->> (rp/mutation :register-profile params)
(rx/finalize #(reset! submitted? false))
(rx/subs (partial handle-register-success form)
(partial handle-register-error form))))))
]
[:& fm/form {:on-submit on-submit
:form form}
[:div.fields-row
[:& fm/input {:name :terms-privacy
[:& fm/input {:name :fullname
:tab-index "1"
:label (tr "auth.fullname")
:type "text"}]]
[:div.fields-row
[:& fm/input {:name :accept-terms-and-privacy
:class "check-primary"
:tab-index "4"
:label (tr "auth.terms-privacy-agreement")
:type "checkbox"}]]
(when (contains? @cf/flags :show-newsletter-check-on-register-validation)
[:div.fields-row
[:& fm/input {:name :accept-newsletter-subscription
:class "check-primary"
:label (tr "auth.terms-privacy-agreement")
:type "checkbox"}]])
[:& fm/submit-button
{:label (tr "auth.register-submit")
:disabled @submitted?}]]))
;; --- Register Page
(mf/defc register-validate-page
[{:keys [params] :as props}]
(prn "register-validate-page" params)
[:div.form-container
[:h1 (tr "auth.register-title")]
[:div.subtitle (tr "auth.register-subtitle")]
[:& register-validate-form {:params params}]
[:div.links
[:div.link-entry
[:a {:on-click #(st/emit! (rt/nav :auth-register {} {}))
:tab-index "4"}
(tr "labels.go-back")]]]])
(mf/defc register-success-page
[{:keys [params] :as props}]
@ -136,32 +257,3 @@
[:div.notification-text-email (:email params "")]
[:div.notification-text (tr "auth.check-your-email")]])
(mf/defc register-page
[{:keys [params] :as props}]
[:div.form-container
[:h1 (tr "auth.register-title")]
[:div.subtitle (tr "auth.register-subtitle")]
(when cfg/demo-warning
[:& demo-warning])
[:& register-form {:params params}]
[:div.links
[:div.link-entry
[:span (tr "auth.already-have-account") " "]
[:a {:on-click #(st/emit! (rt/nav :auth-login {} params))
:tab-index "4"}
(tr "auth.login-here")]]
(when cfg/allow-demo-users
[:div.link-entry
[:span (tr "auth.create-demo-profile") " "]
[:a {:on-click #(st/emit! (du/create-demo-profile))
:tab-index "5"}
(tr "auth.create-demo-account")]])
[:& login/login-buttons {:params params}]]])