Merge branch 'us/newsletter_subscription' into staging

This commit is contained in:
Andrey Antukh 2022-04-04 23:12:03 +02:00
commit 7105255212
19 changed files with 402 additions and 114 deletions

View file

@ -54,11 +54,14 @@
:browser
:webworker))
(def default-flags
[:enable-newsletter-subscription])
(defn- parse-flags
[global]
(let [flags (obj/get global "penpotFlags" "")
flags (sequence (map keyword) (str/words flags))]
(flags/parse flags/default flags)))
(flags/parse flags/default default-flags flags)))
(defn- parse-version
[global]

View file

@ -303,8 +303,8 @@
(watch [_ _ stream]
(let [mdata (meta data)
on-success (:on-success mdata identity)
on-error (:on-error mdata #(rx/throw %))]
(->> (rp/mutation :update-profile data)
on-error (:on-error mdata rx/throw)]
(->> (rp/mutation :update-profile (dissoc data :props))
(rx/catch on-error)
(rx/mapcat
(fn [_]
@ -392,7 +392,6 @@
(->> (rp/mutation :update-profile-props {:props props})
(rx/map (constantly (fetch-profile)))))))))
(defn mark-questions-as-answered
[]
(ptk/reify ::mark-questions-as-answered

View file

@ -59,15 +59,15 @@
klass (str more-classes " "
(dom/classnames
:focus @focus?
:valid (and touched? (not error))
:invalid (and touched? error)
:disabled disabled
:empty (and is-text? (str/empty? value))
:with-icon (not (nil? help-icon'))
:custom-input is-text?
:input-radio is-radio?
:input-checkbox is-checkbox?))
:focus @focus?
:valid (and touched? (not error))
:invalid (and touched? error)
:disabled disabled
:empty (and is-text? (str/empty? value))
:with-icon (not (nil? help-icon'))
:custom-input is-text?
:input-radio is-radio?
:input-checkbox is-checkbox?))
swap-text-password
(fn []
@ -78,7 +78,7 @@
on-focus #(reset! focus? true)
on-change (fn [event]
(let [value (-> event dom/get-target dom/get-input-value)]
(let [value (-> event dom/get-target dom/get-input-value)]
(fm/on-input-change form input-name value trim)))
on-blur
@ -87,16 +87,23 @@
(when-not (get-in @form [:touched input-name])
(swap! form assoc-in [:touched input-name] true)))
on-click
(fn [_]
(when-not (get-in @form [:touched input-name])
(swap! form assoc-in [:touched input-name] true)))
props (-> props
(dissoc :help-icon :form :trim :children)
(assoc :id (name input-name)
:value value
:auto-focus auto-focus?
:on-click (when (or is-radio? is-checkbox?) on-click)
:on-focus on-focus
:on-blur on-blur
:placeholder label
:on-change on-change
:type @type')
(cond-> (and value is-checkbox?) (assoc :default-checked value))
(obj/clj->props))]
[:div
@ -210,7 +217,7 @@
(let [form (or form (mf/use-ctx form-ctx))]
[:input.btn-primary.btn-large
{:name "submit"
:class (when-not (:valid @form) "btn-disabled")
:class (when (or (not (:valid @form)) (true? disabled)) "btn-disabled")
:disabled (or (not (:valid @form)) (true? disabled))
:on-click on-click
:value label

View file

@ -10,6 +10,7 @@
[app.main.data.modal :as modal]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.onboarding.newsletter]
[app.main.ui.onboarding.questions]
[app.main.ui.onboarding.team-choice]
[app.main.ui.onboarding.templates]
@ -134,8 +135,10 @@
[:p (tr "onboarding.slide.3.desc1")]
[:p (tr "onboarding.slide.3.desc2")]]
[:div.modal-navigation
[:button.btn-secondary {:on-click skip
:data-test "slide-3-btn"} (tr "labels.start")]
[:button.btn-secondary
{:on-click skip
:data-test "slide-3-btn"}
(tr "labels.start")]
[:& rc/navigation-bullets
{:slide slide
:navigate navigate
@ -149,23 +152,23 @@
klass (mf/use-state "fadeInDown")
navigate
(mf/use-callback #(reset! slide %))
(mf/use-fn #(reset! slide %))
skip
(mf/use-callback
(st/emitf (modal/hide)
(modal/show {:type :onboarding-choice})
(du/mark-onboarding-as-viewed)))]
(mf/use-fn
#(st/emit! (modal/hide)
(if (contains? @cf/flags :newsletter-subscription)
(modal/show {:type :onboarding-newsletter-modal})
(modal/show {:type :onboarding-choice}))
(du/mark-onboarding-as-viewed)))]
(mf/use-layout-effect
(mf/deps @slide)
(fn []
(when (not= :start @slide)
(reset! klass "fadeIn"))
(let [sem (tm/schedule 300 #(reset! klass nil))]
(fn []
(reset! klass nil)
(tm/dispose! sem)))))
(mf/with-effect [@slide]
(when (not= :start @slide)
(reset! klass "fadeIn"))
(let [sem (tm/schedule 300 #(reset! klass nil))]
(fn []
(reset! klass nil)
(tm/dispose! sem))))
[:div.modal-overlay
[:div.animated {:class @klass}

View file

@ -0,0 +1,47 @@
;; 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) UXBOX Labs SL
(ns app.main.ui.onboarding.newsletter
(:require
[app.main.data.messages :as dm]
[app.main.data.modal :as modal]
[app.main.data.users :as du]
[app.main.store :as st]
[app.util.i18n :as i18n :refer [tr]]
[rumext.alpha :as mf]))
(mf/defc onboarding-newsletter-modal
{::mf/register modal/components
::mf/register-as :onboarding-newsletter-modal}
[]
(let [message (tr "onboarding.newsletter.acceptance-message")
accept
(mf/use-callback
(fn []
(st/emit! (dm/success message)
(modal/show {:type :onboarding-choice})
(du/update-profile-props {:newsletter-subscribed true}))))
decline
(mf/use-callback
(fn []
(st/emit! (modal/show {:type :onboarding-choice})
(du/update-profile-props {:newsletter-subscribed false}))))]
[:div.modal-overlay
[:div.modal-container.onboarding.newsletter.animated.fadeInUp
[:div.modal-top
[:h1.newsletter-title {:data-test "onboarding-newsletter-title"} (tr "onboarding.newsletter.title")]
[:p (tr "onboarding.newsletter.desc")]]
[:div.modal-bottom
[:p (tr "onboarding.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy.html"} (tr "onboarding.newsletter.policy")]]
[:p (tr "onboarding.newsletter.privacy2")]]
[:div.modal-footer
[:button.btn-secondary {:on-click decline} (tr "onboarding.newsletter.decline")]
[:button.btn-primary {:on-click accept} (tr "onboarding.newsletter.accept")]]
[:img.deco.top {:src "images/deco-newsletter.png" :border "0"}]
[:img.deco.newsletter-left {:src "images/deco-news-left.png" :border "0"}]
[:img.deco.newsletter-right {:src "images/deco-news-right.png" :border "0"}]]]))

View file

@ -13,7 +13,7 @@
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.alpha :as mf]))
@ -30,51 +30,51 @@
(defn- on-submit
[form _event]
(let [data (:clean-data @form)
data (cond-> data
(empty? (:lang data))
(assoc :lang nil))
mdata {:on-success (partial on-success form)}]
(st/emit! (du/update-profile (with-meta data mdata)))))
(mf/defc options-form
[{:keys [locale] :as props}]
[]
(let [profile (mf/deref refs/profile)
initial (mf/with-memo [profile]
(update profile :lang #(or % "")))
form (fm/use-form :spec ::options-form
:initial profile)]
:initial initial)]
[:& fm/form {:class "options-form"
:on-submit on-submit
:form form}
[:h2 (t locale "labels.language")]
[:h2 (tr "labels.language")]
[:div.fields-row
[:& fm/select {:options (into [{:label "Auto (browser)" :value "default"}]
[:& fm/select {:options (into [{:label "Auto (browser)" :value ""}]
i18n/supported-locales)
:label (t locale "dashboard.select-ui-language")
:label (tr "dashboard.select-ui-language")
:default ""
:name :lang
:data-test "setting-lang"}]]
;; TODO: Do not show as long as we only have one theme
#_[:h2 (t locale "dashboard.theme-change")]
#_[:h2 (tr "dashboard.theme-change")]
#_[:div.fields-row
[:& fm/select {:label (t locale "dashboard.select-ui-theme")
[:& fm/select {:label (tr "dashboard.select-ui-theme")
:name :theme
:default "default"
:options [{:label "Default" :value "default"}]
:data-test "theme-lang"}]]
[:& fm/submit-button
{:label (t locale "dashboard.update-settings")
{:label (tr "dashboard.update-settings")
:data-test "submit-lang-change"}]]))
;; --- Password Page
(mf/defc options-page
[{:keys [locale]}]
[]
(mf/use-effect
#(dom/set-html-title (tr "title.settings.options")))
[:div.dashboard-settings
[:div.form-container
{:data-test "settings-form"}
[:& options-form {:locale locale}]]])
[:& options-form {}]]])

View file

@ -7,7 +7,7 @@
(ns app.main.ui.settings.profile
(:require
[app.common.spec :as us]
[app.config :as cfg]
[app.config :as cf]
[app.main.data.messages :as dm]
[app.main.data.modal :as modal]
[app.main.data.users :as du]
@ -17,7 +17,7 @@
[app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr t]]
[app.util.i18n :as i18n :refer [tr]]
[cljs.spec.alpha :as s]
[rumext.alpha :as mf]))
@ -40,10 +40,13 @@
;; --- Profile Form
(mf/defc profile-form
[{:keys [locale] :as props}]
[]
(let [profile (mf/deref refs/profile)
form (fm/use-form :spec ::profile-form
:initial profile)]
initial (mf/with-memo [profile]
(let [subscribed? (-> profile :props :newsletter-subscribed)]
(assoc profile :newsletter-subscribed subscribed?)))
form (fm/use-form :spec ::profile-form :initial initial)]
[:& fm/form {:on-submit on-submit
:form form
:class "profile-form"}
@ -51,7 +54,7 @@
[:& fm/input
{:type "text"
:name :fullname
:label (t locale "dashboard.your-name")}]]
:label (tr "dashboard.your-name")}]]
[:div.fields-row
[:& fm/input
@ -59,29 +62,40 @@
:name :email
:disabled true
:help-icon i/at
:label (t locale "dashboard.your-email")}]
:label (tr "dashboard.your-email")}]
[:div.options
[:div.change-email
[:a {:on-click #(modal/show! :change-email {})}
(t locale "dashboard.change-email")]]]]
(tr "dashboard.change-email")]]]]
(when (contains? @cf/flags :newsletter-subscription)
[:div.newsletter-subs
[:p.newsletter-title (tr "dashboard.newsletter-title")]
[:& fm/input {:name :newsletter-subscribed
:class "check-primary"
:type "checkbox"
:label (tr "dashboard.newsletter-msg")}]
[:p.info (tr "onboarding.newsletter.privacy1")
[:a {:target "_blank" :href "https://penpot.app/privacy.html"} (tr "onboarding.newsletter.policy")]]
[:p.info (tr "onboarding.newsletter.privacy2")]])
[:& fm/submit-button
{:label (t locale "dashboard.update-settings")}]
{:label (tr "dashboard.save-settings")
:disabled (empty? (:touched @form))}]
[:div.links
[:div.link-item
[:a {:on-click #(modal/show! :delete-account {})
:data-test "remove-acount-btn"}
(t locale "dashboard.remove-account")]]]]))
(tr "dashboard.remove-account")]]]]))
;; --- Profile Photo Form
(mf/defc profile-photo-form
[{:keys [locale] :as props}]
(let [file-input (mf/use-ref nil)
profile (mf/deref refs/profile)
photo (cfg/resolve-profile-photo-url profile)
(mf/defc profile-photo-form []
(let [file-input (mf/use-ref nil)
profile (mf/deref refs/profile)
photo (cf/resolve-profile-photo-url profile)
on-image-click #(dom/click (mf/ref-val file-input))
on-file-selected
@ -90,7 +104,7 @@
[:form.avatar-form
[:div.image-change-field
[:span.update-overlay {:on-click on-image-click} (t locale "labels.update")]
[:span.update-overlay {:on-click on-image-click} (tr "labels.update")]
[:img {:src photo}]
[:& file-uploader {:accept "image/jpeg,image/png"
:multi false
@ -100,14 +114,11 @@
;; --- Profile Page
(mf/defc profile-page
[{:keys [locale]}]
(mf/use-effect
#(dom/set-html-title (tr "title.settings.profile")))
(mf/defc profile-page []
(mf/with-effect []
(dom/set-html-title (tr "title.settings.profile")))
[:div.dashboard-settings
[:div.form-container.two-columns
[:& profile-photo-form {:locale locale}]
[:& profile-form {:locale locale}]]])
[:& profile-photo-form]
[:& profile-form]]])