mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 15:51:37 -05:00
Merge pull request #2064 from penpot/palba-signin-register-from-shared-link
✨ Signin/Signup from shared link
This commit is contained in:
commit
8f22c421de
11 changed files with 295 additions and 67 deletions
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")]]]]]))
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
106
frontend/src/app/main/ui/viewer/login.cljs
Normal file
106
frontend/src/app/main/ui/viewer/login.cljs
Normal file
|
@ -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]])]]))
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue