diff --git a/CHANGES.md b/CHANGES.md index 0bfdb3e46..080d03815 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - Allow for nested and rotated boards inside other boards and groups [Taiga #2874](https://tree.taiga.io/project/penpot/us/2874?milestone=319982) - View mode improvements to enable access and use in different conditions [Taiga #3023](https://tree.taiga.io/project/penpot/us/3023) - Improved share link options. Now you can allow non-team members to comment and/or inspect [Taiga #3056] (https://tree.taiga.io/project/penpot/us/3056) +- Signin/Signup from shared link [Taiga #3472](https://tree.taiga.io/project/penpot/us/3472) ### :bug: Bugs fixed ### :arrow_up: Deps updates diff --git a/backend/src/app/rpc/queries/files.clj b/backend/src/app/rpc/queries/files.clj index 9460be08f..18ec92848 100644 --- a/backend/src/app/rpc/queries/files.clj +++ b/backend/src/app/rpc/queries/files.clj @@ -85,7 +85,8 @@ :is-owner is-owner :is-admin (or is-owner is-admin) :can-edit (or is-owner is-admin can-edit) - :can-read true}))) + :can-read true + :is-logged (some? profile-id)}))) ([conn profile-id file-id share-id] (let [perms (get-permissions conn profile-id file-id) ldata (retrieve-share-link conn file-id share-id)] diff --git a/frontend/resources/styles/main/partials/modal.scss b/frontend/resources/styles/main/partials/modal.scss index b6bce0d27..89f4927ca 100644 --- a/frontend/resources/styles/main/partials/modal.scss +++ b/frontend/resources/styles/main/partials/modal.scss @@ -1632,3 +1632,65 @@ } } } + +//- LOGIN +.login-register { + background-color: $color-white; + box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2); + display: flex; + font-family: "worksans", sans-serif; + width: 472px; + height: auto; + position: relative; + + .title { + margin-left: 32px; + h2 { + font-size: 24px; + color: $color-black; + line-height: $fs36; + letter-spacing: 0px; + margin: 0 30px 20px 0; + } + + .modal-close-button { + margin-top: 7px; + margin-right: 12px; + justify-content: right; + svg { + fill: $color-black; + } + } + } + + .modal-bottom { + margin: 0 32px; + color: #1f1f1f; + display: flex; + flex-direction: column; + + &.auth-content { + align-items: initial; + height: auto; + } + + .links { + margin: 7px 0 0 0; + text-align: left; + } + } + + .modal-footer { + justify-content: center; + align-items: center; + + .terms-login { + position: relative; + bottom: 0; + } + } + + .hint { + color: #b1b2b5; + } +} diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 8c9cc7b0a..098386c24 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -63,7 +63,7 @@ (on-error error))))))) (mf/defc login-form - [{:keys [params] :as props}] + [{:keys [params on-success-callback] :as props}] (let [initial (mf/use-memo (mf/deps params) (constantly params)) error (mf/use-state false) @@ -73,10 +73,17 @@ (fn [_] (reset! error (tr "errors.wrong-credentials"))) - on-succes + on-success-default (fn [data] (when-let [token (:invitation-token data)] (st/emit! (rt/nav :auth-verify-token {} {:token token})))) + + on-success + (fn [data] + (if (nil? on-success-callback) + (on-success-default data) + (on-success-callback) + )) on-submit (mf/use-callback @@ -84,7 +91,7 @@ (reset! error nil) (let [params (with-meta (:clean-data @form) {:on-error on-error - :on-success on-succes})] + :on-success on-success})] (st/emit! (du/login params))))) on-submit-ldap @@ -95,7 +102,7 @@ (let [params (:clean-data @form)] (login-with-ldap event (with-meta params {:on-error on-error - :on-success on-succes})))))] + :on-success on-success})))))] [:* (when-let [message @error] [:& msgs/inline-banner @@ -165,32 +172,37 @@ [:a {:on-click #(login-with-oauth % :oidc params)} (tr "auth.login-with-oidc-submit")]])) +(mf/defc login-methods + [{:keys [params on-success-callback] :as props}] + [:* + (when show-alt-login-buttons? + [:* + [:span.separator + [:span.line] + [:span.text (tr "labels.continue-with")] + [:span.line]] + + [:div.buttons + [:& login-buttons {:params params}]] + + (when (or (contains? @cf/flags :login) + (contains? @cf/flags :login-with-ldap)) + [:span.separator + [:span.line] + [:span.text (tr "labels.or")] + [:span.line]])]) + + (when (or (contains? @cf/flags :login) + (contains? @cf/flags :login-with-ldap)) + [:& login-form {:params params :on-success-callback on-success-callback}])]) + (mf/defc login-page [{:keys [params] :as props}] [:div.generic-form.login-form [:div.form-container [:h1 {:data-test "login-title"} (tr "auth.login-title")] - (when show-alt-login-buttons? - [:* - [:span.separator - [:span.line] - [:span.text (tr "labels.continue-with")] - [:span.line]] - - [:div.buttons - [:& login-buttons {:params params}]] - - (when (or (contains? @cf/flags :login) - (contains? @cf/flags :login-with-ldap)) - [:span.separator - [:span.line] - [:span.text (tr "labels.or")] - [:span.line]])]) - - (when (or (contains? @cf/flags :login) - (contains? @cf/flags :login-with-ldap)) - [:& login-form {:params params}]) + [:& login-methods {:params params}] [:div.links (when (contains? @cf/flags :login) diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index 6477cfb32..436f7cded 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -22,15 +22,19 @@ (s/def ::recovery-request-form (s/keys :req-un [::email])) (mf/defc recovery-form - [] + [{:keys [on-success-callback] :as props}] (let [form (fm/use-form :spec ::recovery-request-form :initial {}) submitted (mf/use-state false) + default-success-finish #(st/emit! (dm/info (tr "auth.notifications.recovery-token-sent"))) + on-success (mf/use-callback - (fn [_ _] + (fn [cdata _] (reset! submitted false) - (st/emit! (dm/info (tr "auth.notifications.recovery-token-sent"))))) + (if (nil? on-success-callback) + (default-success-finish) + (on-success-callback (:email cdata))))) on-error (mf/use-callback @@ -74,15 +78,17 @@ ;; --- Recovery Request Page (mf/defc recovery-request-page - [] - [:section.generic-form - [:div.form-container - [:h1 (tr "auth.recovery-request-title")] - [:div.subtitle (tr "auth.recovery-request-subtitle")] - [:& recovery-form] + [{:keys [params on-success-callback go-back-callback] :as props}] + (let [default-go-back #(st/emit! (rt/nav :auth-login)) + go-back (or go-back-callback default-go-back)] + [:section.generic-form + [:div.form-container + [:h1 (tr "auth.recovery-request-title")] + [:div.subtitle (tr "auth.recovery-request-subtitle")] + [:& recovery-form {:params params :on-success-callback on-success-callback}] - [:div.links - [:div.link-entry - [:a {:on-click #(st/emit! (rt/nav :auth-login)) - :data-test "go-back-link"} - (tr "labels.go-back")]]]]]) + [:div.links + [:div.link-entry + [:a {:on-click go-back + :data-test "go-back-link"} + (tr "labels.go-back")]]]]])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 739b7ad1d..a88fa3737 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -68,17 +68,23 @@ (st/emit! (dm/error (tr "errors.generic"))))) (defn- handle-prepare-register-success - [_ params] + [params] (st/emit! (rt/nav :auth-register-validate {} params))) + (mf/defc register-form - [{:keys [params] :as props}] + [{:keys [params on-success-callback] :as props}] (let [initial (mf/use-memo (mf/deps params) (constantly params)) form (fm/use-form :spec ::register-form :validators [validate] :initial initial) submitted? (mf/use-state false) + on-success (fn [p] + (if (nil? on-success-callback) + (handle-prepare-register-success p) + (on-success-callback p))) + on-submit (mf/use-callback (fn [form _event] @@ -87,9 +93,9 @@ (->> (rp/mutation :prepare-register-profile cdata) (rx/map #(merge % params)) (rx/finalize #(reset! submitted? false)) - (rx/subs (partial handle-prepare-register-success form) - (partial handle-prepare-register-error form)))))) - ] + (rx/subs + on-success + (partial handle-prepare-register-error form))))))] [:& fm/form {:on-submit on-submit @@ -113,15 +119,10 @@ :disabled @submitted? :data-test "register-form-submit"}]])) -(mf/defc register-page - [{:keys [params] :as props}] - [:div.form-container - [:h1 {:data-test "registration-title"} (tr "auth.register-title")] - [:div.subtitle (tr "auth.register-subtitle")] - - (when (contains? @cf/flags :demo-warning) - [:& demo-warning]) +(mf/defc register-methods + [{:keys [params on-success-callback] :as props}] + [:* (when login/show-alt-login-buttons? [:* [:span.separator @@ -139,7 +140,19 @@ [:span.text (tr "labels.or")] [:span.line]])]) - [:& register-form {:params params}] + [:& register-form {:params params :on-success-callback on-success-callback}]]) + +(mf/defc register-page + [{:keys [params] :as props}] + [:div.form-container + + [:h1 {:data-test "registration-title"} (tr "auth.register-title")] + [:div.subtitle (tr "auth.register-subtitle")] + + (when (contains? @cf/flags :demo-warning) + [:& demo-warning]) + + [:& register-methods {:params params}] [:div.links [:div.link-entry @@ -170,7 +183,7 @@ (st/emit! (dm/error (tr "errors.generic")))))) (defn- handle-register-success - [_form data] + [data] (cond (some? (:invitation-token data)) (let [token (:invitation-token data)] @@ -197,11 +210,16 @@ ::accept-newsletter-subscription]))) (mf/defc register-validate-form - [{:keys [params] :as props}] + [{:keys [params on-success-callback] :as props}] (let [form (fm/use-form :spec ::register-validate-form :initial params) submitted? (mf/use-state false) + on-success (fn [p] + (if (nil? on-success-callback) + (handle-register-success p) + (on-success-callback (:email p)))) + on-submit (mf/use-callback (fn [form _event] @@ -209,9 +227,8 @@ (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)))))) - ] + (rx/subs on-success + (partial handle-register-error form))))))] [:& fm/form {:on-submit on-submit :form form} diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index 6ccbc169c..f2f86ace9 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -29,6 +29,7 @@ [app.main.ui.viewer.handoff :as handoff] [app.main.ui.viewer.header :refer [header]] [app.main.ui.viewer.interactions :as interactions] + [app.main.ui.viewer.login] [app.main.ui.viewer.thumbnails :refer [thumbnails-panel]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -252,8 +253,9 @@ (when (nil? page) (ex/raise :type :not-found)) - (when (not allowed) - (st/emit! (dv/go-to-section :interactions))) + (mf/with-effect [] + (when (not allowed) + (st/emit! (dv/go-to-section :interactions)))) ;; Set the page title (mf/use-effect diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index 5cde91686..034473649 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -21,6 +21,10 @@ [app.util.i18n :refer [tr]] [rumext.alpha :as mf])) +(defn open-login-dialog + [] + (modal/show! :login-register {})) + (mf/defc zoom-widget {::mf/wrap [mf/memo]} [{:keys [zoom @@ -111,7 +115,10 @@ [:span.btn-primary {:on-click open-share-dialog} i/export [:span (tr "labels.share-prototype")]]) (when (:can-edit permissions) - [:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])])) + [:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")]) + + (when-not (:is-logged permissions) + [:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])])) (mf/defc header-sitemap [{:keys [project file page frame] :as props}] @@ -176,12 +183,16 @@ #(st/emit! (dv/go-to-dashboard)) go-to-handoff - (fn [] - (st/emit! dv/close-thumbnails-panel (dv/go-to-section :handoff))) + (fn[] + (if (:is-logged permissions) + (st/emit! dv/close-thumbnails-panel (dv/go-to-section :handoff)) + (open-login-dialog))) navigate (fn [section] - (st/emit! (dv/go-to-section section)))] + (if (or (= section :interactions) (:is-logged permissions)) + (st/emit! (dv/go-to-section section)) + (open-login-dialog)))] [:header.viewer-header [:div.nav-zone @@ -200,8 +211,7 @@ i/play] (when (or (:can-edit permissions) - (and (true? (:is-logged permissions)) - (= (:who-comment permissions) "all"))) + (= (:who-comment permissions) "all")) [:button.mode-zone-button.tooltip.tooltip-bottom {:on-click #(navigate :comments) :class (dom/classnames :active (= section :comments)) @@ -210,7 +220,6 @@ (when (or (= (:type permissions) :membership) (and (= (:type permissions) :share-link) - (true? (:is-logged permissions)) (= (:who-inspect permissions) "all"))) [:button.mode-zone-button.tooltip.tooltip-bottom {:on-click go-to-handoff diff --git a/frontend/src/app/main/ui/viewer/login.cljs b/frontend/src/app/main/ui/viewer/login.cljs new file mode 100644 index 000000000..0745a3c5f --- /dev/null +++ b/frontend/src/app/main/ui/viewer/login.cljs @@ -0,0 +1,106 @@ +;; 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.viewer.login + (:require + [app.common.logging :as log] + [app.main.data.modal :as modal] + [app.main.store :as st] + [app.main.ui.auth :refer [terms-login]] + [app.main.ui.auth.login :refer [login-methods]] + [app.main.ui.auth.recovery-request :refer [recovery-request-page]] + [app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page]] + [app.main.ui.icons :as i] + [app.util.dom :as dom] + [app.util.i18n :as i18n :refer [tr]] + [app.util.storage :refer [storage]] + [rumext.alpha :as mf])) + +(log/set-level! :warn) + +(mf/defc login-register-modal + {::mf/register modal/components + ::mf/register-as :login-register} + [_] + (let [uri (. (. js/document -location) -href) + user-email (mf/use-state "") + register-token (mf/use-state "") + current-section (mf/use-state :login) + set-current-section (mf/use-fn #(reset! current-section %)) + main-section (or + (= @current-section :login) + (= @current-section :register) + (= @current-section :register-validate)) + close + (fn [event] + (dom/prevent-default event) + (st/emit! (modal/hide))) + success-email-sent + (fn [email] + (reset! user-email email) + (set-current-section :email-sent)) + success-login + (fn [] + (.reload js/window.location true)) + success-register + (fn [data] + (reset! register-token (:token data)) + (set-current-section :register-validate))] + (mf/with-effect [] + (swap! storage assoc :redirect-url uri)) + + [:div.modal-overlay + [:div.modal-container.login-register + [:div.title + [:div.modal-close-button {:on-click close :title (tr "labels.close")} + i/close] + (when main-section + [:h2 (tr "labels.continue-with-penpot")])] + + [:div.modal-bottom.auth-content + + (case @current-section + :login + [:div.generic-form.login-form + [:div.form-container + [:& login-methods {:on-success-callback success-login}] + [:div.links + [:div.link-entry + [:a {:on-click #(set-current-section :recovery-request)} + (tr "auth.forgot-password")]] + [:div.link-entry + [:span (tr "auth.register") " "] + [:a {:on-click #(set-current-section :register)} + (tr "auth.register-submit")]]]]] + + :register + [:div.form-container + [:& register-methods {:on-success-callback success-register}] + [:div.links + [:div.link-entry + [:span (tr "auth.already-have-account") " "] + [:a {:on-click #(set-current-section :login)} + (tr "auth.login-here")]]]] + + :register-validate + [:div.form-container + [:& register-validate-form {:params {:token @register-token} + :on-success-callback success-email-sent}] + [:div.links + [:div.link-entry + [:a {:on-click #(set-current-section :register)} + (tr "labels.go-back")]]]] + + :recovery-request + [:& recovery-request-page {:go-back-callback #(set-current-section :login) + :on-success-callback success-email-sent}] + :email-sent + [:div.form-container + [:& register-success-page {:params {:email @user-email}}]])] + + (when main-section + [:div.modal-footer.links + [:& terms-login]])]])) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 3ae8bfe83..99b91eafd 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1101,6 +1101,9 @@ msgstr "Continue" msgid "labels.continue-with" msgstr "Continue with" +msgid "labels.continue-with-penpot" +msgstr "You can continue with a Penpot account" + #: src/app/main/ui/workspace/sidebar/assets.cljs msgid "labels.create" msgstr "Create" @@ -1208,6 +1211,9 @@ msgstr "Help Center" msgid "labels.hide-resolved-comments" msgstr "Hide resolved comments" +msgid "labels.log-or-sign" +msgstr "Log in or sign up" + msgid "labels.show-comments-list" msgstr "Show comments list" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index dcc6ab4bf..ad8af9bdf 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1158,6 +1158,9 @@ msgstr "Continuar" msgid "labels.continue-with" msgstr "ContinĂșa con" +msgid "labels.continue-with-penpot" +msgstr "Puedes continuar con una cuenta de Penpot" + #: src/app/main/ui/workspace/sidebar/assets.cljs msgid "labels.create" msgstr "Crear" @@ -1272,6 +1275,9 @@ msgstr "Centro de ayuda" msgid "labels.hide-resolved-comments" msgstr "Ocultar comentarios resueltos" +msgid "labels.log-or-sign" +msgstr "Entra o regĂ­strate" + msgid "labels.show-comments-list" msgstr "Mostrar lista de comentarios"