diff --git a/frontend/resources/images/login-pink.svg b/frontend/resources/images/login-pink.svg index f633fd411..de7e40a93 100644 --- a/frontend/resources/images/login-pink.svg +++ b/frontend/resources/images/login-pink.svg @@ -1,158 +1,790 @@ - - - - - - - + + + + + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - + + + + + - - - - - - - + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - - - - - - - + + + + + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - S - - - V - - - G - + + + + - - + + diff --git a/frontend/resources/styles/common/base.scss b/frontend/resources/styles/common/base.scss index f49c00064..4dafb79d5 100644 --- a/frontend/resources/styles/common/base.scss +++ b/frontend/resources/styles/common/base.scss @@ -54,17 +54,13 @@ svg { } } -*:focus { - outline: none; - box-shadow: 0; -} - a { cursor: pointer; - color: $color-primary-dark; + font-weight: 500; + color: $color-gray-50; &:hover { - color: $color-primary; + text-decoration: underline; } } diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss index 0a7c0032f..df56e139d 100644 --- a/frontend/resources/styles/common/framework.scss +++ b/frontend/resources/styles/common/framework.scss @@ -14,6 +14,7 @@ border-radius: 3px; cursor: pointer; display: flex; + font-family: "worksans", sans-serif; font-size: $fs12; height: 30px; justify-content: center; @@ -42,7 +43,8 @@ @extend %btn; background: $color-primary; color: $color-black; - &:hover { + &:hover, + &:focus { background: $color-black; color: $color-primary; } @@ -503,16 +505,6 @@ input[type="checkbox"] { margin-top: 1px 0 0; } -input:focus, -select:focus, -textarea:focus, -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - box-shadow: none; - outline: none; -} - .form-errors { color: $color-danger; } diff --git a/frontend/resources/styles/main/layouts/login.scss b/frontend/resources/styles/main/layouts/login.scss index 3d88adb37..7fdc92ed5 100644 --- a/frontend/resources/styles/main/layouts/login.scss +++ b/frontend/resources/styles/main/layouts/login.scss @@ -87,7 +87,6 @@ .btn-large { flex-grow: 1; font-size: 14px; - font-family: sourcesanspro; font-style: normal; font-weight: normal; } @@ -102,7 +101,8 @@ height: 20px; margin-right: 1rem; } - &:hover { + &:hover, + &:focus { background-color: #2065d7; color: $color-white; } @@ -120,7 +120,8 @@ margin-right: 1rem; } - &:hover { + &:hover, + &:focus { background-color: #ee5f18; color: $color-white; } @@ -138,7 +139,8 @@ margin-right: 1rem; } - &:hover { + &:hover, + &:focus { background-color: #2f2f2f; color: $color-white; } @@ -186,7 +188,12 @@ margin-bottom: 10px; a { font-size: $fs14; - color: $color-primary-dark; + font-weight: 500; + color: $color-gray-50; + &:hover, + &:focus { + text-decoration: underline; + } } } } @@ -198,6 +205,7 @@ span { margin: 0 $size-2; + color: $color-gray-40; } } } diff --git a/frontend/resources/styles/main/partials/dashboard.scss b/frontend/resources/styles/main/partials/dashboard.scss index 8fe5e2ebe..f18499919 100644 --- a/frontend/resources/styles/main/partials/dashboard.scss +++ b/frontend/resources/styles/main/partials/dashboard.scss @@ -89,9 +89,9 @@ margin-bottom: 8px; } .info { - color: $color-gray-30; + color: $color-gray-50; margin-bottom: 20px; - font-size: $fs16; + font-size: $fs14; } } .action { @@ -551,6 +551,10 @@ width: 16px; height: 16px; } + span { + font-weight: 500; + font-size: $fs14; + } } .template-link { @@ -567,7 +571,8 @@ .template-link-text { font-size: 12px; - color: $color-gray-30; + margin-top: $size-2; + color: $color-gray-50; } &:hover { diff --git a/frontend/resources/styles/main/partials/forms.scss b/frontend/resources/styles/main/partials/forms.scss index 7be087539..47891adbc 100644 --- a/frontend/resources/styles/main/partials/forms.scss +++ b/frontend/resources/styles/main/partials/forms.scss @@ -99,7 +99,9 @@ textarea { } a { - text-decoration: underline; + &:hover { + text-decoration: underline; + } } p { @@ -146,7 +148,7 @@ textarea { label { font-size: $fs12; - color: $color-gray-30; + color: $color-gray-50; position: absolute; left: 15px; top: 6px; @@ -216,6 +218,7 @@ textarea { } .hint { + color: $color-gray-40; padding: 4px; font-size: $fs12; } diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs index 67a8e8d6f..03d1061d3 100644 --- a/frontend/src/app/main/ui/auth.cljs +++ b/frontend/src/app/main/ui/auth.cljs @@ -41,9 +41,9 @@ (mf/use-effect #(dom/set-html-title (tr "title.default"))) - [:div.auth + [:main.auth [:section.auth-sidebar - [:a.logo {:href "#/"} i/logo] + [:span.logo {:aria-hidden "true"} i/logo] [:span.tagline (tr "auth.sidebar-tagline")]] [:section.auth-content diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 29273386d..baac56f6f 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -6,17 +6,21 @@ (ns app.main.ui.auth.login (:require + [app.common.data :as d] [app.common.spec :as us] [app.config :as cf] [app.main.data.messages :as dm] [app.main.data.users :as du] [app.main.repo :as rp] [app.main.store :as st] + [app.main.ui.components.button-link :as bl] [app.main.ui.components.forms :as fm] + [app.main.ui.components.link :as lk] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.dom :as dom] [app.util.i18n :refer [tr]] + [app.util.keyboard :as k] [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] @@ -29,14 +33,6 @@ :login-with-gitlab :login-with-oidc])) -(s/def ::email ::us/email) -(s/def ::password ::us/not-empty-string) -(s/def ::invitation-token ::us/not-empty-string) - -(s/def ::login-form - (s/keys :req-un [::email ::password] - :opt-un [::invitation-token])) - (defn- login-with-oidc [event provider params] (dom/prevent-default event) @@ -74,13 +70,30 @@ :else (st/emit! (dm/error (tr "errors.generic"))))))))) +(s/def ::email ::us/email) +(s/def ::password ::us/not-empty-string) +(s/def ::invitation-token ::us/not-empty-string) + +(s/def ::login-form + (s/keys :req-un [::email ::password] + :opt-un [::invitation-token])) + +(defn handle-error-messages + [errors _data] + (d/update-when errors :email + (fn [{:keys [code] :as error}] + (cond-> error + (= code ::us/email) + (assoc :message (tr "errors.email-invalid")))))) (mf/defc login-form [{:keys [params on-success-callback] :as props}] (let [initial (mf/use-memo (mf/deps params) (constantly params)) error (mf/use-state false) - form (fm/use-form :spec ::login-form :initial initial) + form (fm/use-form :spec ::login-form + :validators [handle-error-messages] + :initial initial) on-error (fn [cause] @@ -109,8 +122,7 @@ (fn [data] (if (nil? on-success-callback) (on-success-default data) - (on-success-callback) - )) + (on-success-callback))) on-submit (mf/use-callback @@ -136,21 +148,21 @@ {:type :warning :content message :on-close #(reset! error nil) - :data-test "login-banner"}]) + :data-test "login-banner" + :role "alert"}]) [:& fm/form {:on-submit on-submit :form form} [:div.fields-row [:& fm/input {:name :email :type "email" - :tab-index "2" :help-icon i/at :label (tr "auth.email")}]] + [:div.fields-row [:& fm/input {:type "password" :name :password - :tab-index "3" :help-icon i/eye :label (tr "auth.password")}]] @@ -169,34 +181,38 @@ [{:keys [params] :as props}] [:div.auth-buttons (when (contains? @cf/flags :login-with-google) - [:a.btn-primary.btn-large.btn-google-auth - {:on-click #(login-with-oidc % :google params)} - [:span.logo i/brand-google] - (tr "auth.login-with-google-submit")]) + [:& bl/button-link {:action #(login-with-oidc % :google params) + :icon i/brand-google + :name (tr "auth.login-with-google-submit") + :klass "btn-google-auth"}]) (when (contains? @cf/flags :login-with-github) - [:a.btn-primary.btn-large.btn-github-auth - {:on-click #(login-with-oidc % :github params)} - [:span.logo i/brand-github] - (tr "auth.login-with-github-submit")]) + [:& bl/button-link {:action #(login-with-oidc % :github params) + :icon i/brand-github + :name (tr "auth.login-with-github-submit") + :klass "btn-github-auth"}]) (when (contains? @cf/flags :login-with-gitlab) - [:a.btn-primary.btn-large.btn-gitlab-auth - {:on-click #(login-with-oidc % :gitlab params)} - [:span.logo i/brand-gitlab] - (tr "auth.login-with-gitlab-submit")]) + [:& bl/button-link {:action #(login-with-oidc % :gitlab params) + :icon i/brand-gitlab + :name (tr "auth.login-with-gitlab-submit") + :klass "btn-gitlab-auth"}]) (when (contains? @cf/flags :login-with-oidc) - [:a.btn-primary.btn-large.btn-github-auth - {:on-click #(login-with-oidc % :oidc params)} - [:span.logo i/brand-openid] - (tr "auth.login-with-oidc-submit")])]) + [:& bl/button-link {:action #(login-with-oidc % :oidc params) + :icon i/brand-openid + :name (tr "auth.login-with-oidc-submit") + :klass "btn-github-auth"}])]) (mf/defc login-button-oidc [{:keys [params] :as props}] (when (contains? @cf/flags :login-with-oidc) [:div.link-entry.link-oidc - [:a {:on-click #(login-with-oidc % :oidc params)} + [:a {:tab-index "0" + :on-key-down (fn [event] + (when (k/enter? event) + (login-with-oidc event :oidc params))) + :on-click #(login-with-oidc % :oidc params)} (tr "auth.login-with-oidc-submit")]])) (mf/defc login-methods @@ -209,8 +225,7 @@ [:span.text (tr "labels.continue-with")] [:span.line]] - [:div.buttons - [:& login-buttons {:params params}]] + [:& login-buttons {:params params}] (when (or (contains? @cf/flags :login) (contains? @cf/flags :login-with-ldap)) @@ -234,21 +249,21 @@ [:div.links (when (contains? @cf/flags :login) [:div.link-entry - [:a {:on-click #(st/emit! (rt/nav :auth-recovery-request)) - :data-test "forgot-password"} - (tr "auth.forgot-password")]]) + [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request)) + :name (tr "auth.forgot-password") + :data-test "forgot-password"}]]) (when (contains? @cf/flags :registration) [:div.link-entry [:span (tr "auth.register") " "] - [:a {:on-click #(st/emit! (rt/nav :auth-register {} params)) - :data-test "register-submit"} - (tr "auth.register-submit")]])] + [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params)) + :name (tr "auth.register-submit") + :data-test "register-submit"}]])] (when (contains? @cf/flags :demo-users) [:div.links.demo [:div.link-entry [:span (tr "auth.create-demo-profile") " "] - [:a {:on-click #(st/emit! (du/create-demo-profile)) - :data-test "demo-account-link"} - (tr "auth.create-demo-account")]]])]]) + [:& lk/link {:action #(st/emit! (du/create-demo-profile)) + :name (tr "auth.create-demo-account") + :data-test "demo-account-link"}]]])]]) diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs index f72bf420a..3f752f7f6 100644 --- a/frontend/src/app/main/ui/auth/recovery.cljs +++ b/frontend/src/app/main/ui/auth/recovery.cljs @@ -25,10 +25,10 @@ ::password-2])) (defn- password-equality - [data] + [errors data] (let [password-1 (:password-1 data) password-2 (:password-2 data)] - (cond-> {} + (cond-> errors (and password-1 password-2 (not= password-1 password-2)) (assoc :password-2 {:message "errors.password-invalid-confirmation"}) diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index 783d2fb95..6356c5de2 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -6,11 +6,13 @@ (ns app.main.ui.auth.recovery-request (:require + [app.common.data :as d] [app.common.spec :as us] [app.main.data.messages :as dm] [app.main.data.users :as du] [app.main.store :as st] [app.main.ui.components.forms :as fm] + [app.main.ui.components.link :as lk] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] @@ -20,10 +22,19 @@ (s/def ::email ::us/email) (s/def ::recovery-request-form (s/keys :req-un [::email])) +(defn handle-error-messages + [errors _data] + (d/update-when errors :email + (fn [{:keys [code] :as error}] + (cond-> error + (= code :missing) + (assoc :message (tr "errors.email-invalid")))))) (mf/defc recovery-form [{:keys [on-success-callback] :as props}] - (let [form (fm/use-form :spec ::recovery-request-form :initial {}) + (let [form (fm/use-form :spec ::recovery-request-form + :validators [handle-error-messages] + :initial {}) submitted (mf/use-state false) default-success-finish #(st/emit! (dm/info (tr "auth.notifications.recovery-token-sent"))) @@ -87,9 +98,8 @@ [: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 go-back - :data-test "go-back-link"} - (tr "labels.go-back")]]]]])) + [:& lk/link {:action go-back + :name (tr "labels.go-back") + :data-test "go-back-link"}]]]]])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 87ab67dde..38d9bf3ca 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.auth.register (:require + [app.common.data :as d] [app.common.spec :as us] [app.config :as cf] [app.main.data.messages :as dm] @@ -14,6 +15,7 @@ [app.main.store :as st] [app.main.ui.auth.login :as login] [app.main.ui.components.forms :as fm] + [app.main.ui.components.link :as lk] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :refer [tr]] @@ -31,11 +33,17 @@ ;; --- PAGE: Register (defn- validate - [data] + [errors data] (let [password (:password data)] - (cond-> {} + (cond-> errors (> 8 (count password)) - (assoc :password {:message "errors.password-too-short"})))) + (assoc :password {:message "errors.password-too-short"}) + :always + (d/update-when :email + (fn [{:keys [code] :as error}] + (cond-> error + (= code ::us/email) + (assoc :message (tr "errors.email-invalid")))))))) (s/def ::fullname ::us/not-empty-string) (s/def ::password ::us/not-empty-string) @@ -106,13 +114,11 @@ [:div.fields-row [:& fm/input {:type "email" :name :email - :tab-index "2" :help-icon i/at :label (tr "auth.email") :data-test "email-input"}]] [:div.fields-row [:& fm/input {:name :password - :tab-index "3" :hint (tr "auth.password-length-hint") :label (tr "auth.password") :type "password"}]] @@ -133,8 +139,7 @@ [:span.text (tr "labels.continue-with")] [:span.line]] - [:div.buttons - [:& login/login-buttons {:params params}]] + [:& login/login-buttons {:params params}] (when (or (contains? @cf/flags :login) (contains? @cf/flags :login-with-ldap)) @@ -160,17 +165,16 @@ [:div.links [:div.link-entry [:span (tr "auth.already-have-account") " "] - [:a {:on-click #(st/emit! (rt/nav :auth-login {} params)) - :tab-index "4" - :data-test "login-here-link"} - (tr "auth.login-here")]] + + [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params)) + :name (tr "auth.login-here") + :data-test "login-here-link"}]] (when (contains? @cf/flags :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")]])]]) + [:& lk/link {:action #(st/emit! (du/create-demo-profile)) + :name (tr "auth.create-demo-account")}]])]]) ;; --- PAGE: register validation @@ -237,7 +241,6 @@ :form form} [:div.fields-row [:& fm/input {:name :fullname - :tab-index "1" :label (tr "auth.fullname") :type "text"}]] @@ -268,9 +271,8 @@ [:div.links [:div.link-entry - [:a {:on-click #(st/emit! (rt/nav :auth-register {} {})) - :tab-index "4"} - (tr "labels.go-back")]]]]) + [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {})) + :name (tr "labels.go-back")}]]]]) (mf/defc register-success-page [{:keys [params] :as props}] diff --git a/frontend/src/app/main/ui/components/button_link.cljs b/frontend/src/app/main/ui/components/button_link.cljs new file mode 100644 index 000000000..66cd2c395 --- /dev/null +++ b/frontend/src/app/main/ui/components/button_link.cljs @@ -0,0 +1,21 @@ +;; 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) KALEIDOS INC + +(ns app.main.ui.components.button-link + (:require + [app.util.keyboard :as kbd] + [rumext.v2 :as mf])) + +(mf/defc button-link [{:keys [action icon name klass]}] + [:a.btn-primary.btn-large.button-link + {:class klass + :tabindex "0" + :on-click action + :on-key-down (fn [event] + (when (kbd/enter? event) + (action event)))} + [:span.logo icon] + name]) diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs index 4102c36d9..176f99d78 100644 --- a/frontend/src/app/main/ui/components/forms.cljs +++ b/frontend/src/app/main/ui/components/forms.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.components.forms (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.ui.hooks :as hooks] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -42,7 +43,6 @@ touched? (get-in @form [:touched input-name]) error (get-in @form [:errors input-name]) - value (get-in @form [:data input-name] "") help-icon' (cond @@ -103,8 +103,11 @@ :on-blur on-blur :placeholder label :on-change on-change - :type @type') - (cond-> (and value is-checkbox?) (assoc :default-checked value)) + :type @type' + :tabindex "0") + (cond-> (and value is-checkbox?) (assoc :default-checked value)) + (cond-> (and touched? (:message error)) (assoc "aria-invalid" "true" + "aria-describedby" (dm/str "error-" input-name))) (obj/clj->props))] [:div @@ -126,7 +129,8 @@ help-icon']) (cond (and touched? (:message error)) - [:span.error {:data-test (clojure.string/join [data-test "-error"]) }(tr (:message error))] + [:span.error {:id (dm/str "error-" input-name) + :data-test (clojure.string/join [data-test "-error"]) }(tr (:message error))] (string? hint) [:span.hint hint])]])) @@ -220,7 +224,11 @@ {:name "submit" :class (when (or (not (:valid @form)) (true? disabled)) "btn-disabled") :disabled (or (not (:valid @form)) (true? disabled)) + :tabindex "0" :on-click on-click + :on-key-down (fn [event] + (when (kbd/enter? event) + (on-click))) :value label :data-test data-test :type "submit"}])) diff --git a/frontend/src/app/main/ui/components/link.cljs b/frontend/src/app/main/ui/components/link.cljs new file mode 100644 index 000000000..2b9c19184 --- /dev/null +++ b/frontend/src/app/main/ui/components/link.cljs @@ -0,0 +1,20 @@ +;; 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) KALEIDOS INC + +(ns app.main.ui.components.link + (:require + [app.util.keyboard :as kbd] + [rumext.v2 :as mf])) + +(mf/defc link [{:keys [action name klass data-test]}] + [:a {:on-click action + :klass klass + :on-key-down (fn [event] + (when (kbd/enter? event) + (action event))) + :tabindex "0" + :data-test data-test} + name]) diff --git a/frontend/src/app/main/ui/messages.cljs b/frontend/src/app/main/ui/messages.cljs index 49be805dd..ae7e53930 100644 --- a/frontend/src/app/main/ui/messages.cljs +++ b/frontend/src/app/main/ui/messages.cljs @@ -15,7 +15,7 @@ [rumext.v2 :as mf])) (mf/defc banner - [{:keys [type position status controls content actions on-close data-test] :as props}] + [{:keys [type position status controls content actions on-close data-test role] :as props}] [:div.banner {:class (dom/classnames :warning (= type :warning) :error (= type :error) @@ -35,7 +35,8 @@ [:div.content {:class (dom/classnames :inline-actions (= controls :inline-actions) :bottom-actions (= controls :bottom-actions)) - :data-test data-test} + :data-test data-test + :role role} content (when (or (= controls :bottom-actions) (= controls :inline-actions)) [:div.actions @@ -60,7 +61,7 @@ (mf/defc inline-banner {::mf/wrap [mf/memo]} - [{:keys [type content on-close actions data-test] :as props}] + [{:keys [type content on-close actions data-test role] :as props}] [:& banner {:type type :position :inline :status :visible @@ -72,5 +73,6 @@ :content content :on-close on-close :actions actions - :data-test data-test}]) + :data-test data-test + :role role}]) diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 468f18dde..3bca85224 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -24,10 +24,10 @@ (s/def ::email-2 ::us/email) (defn- email-equality - [data] + [errors data] (let [email-1 (:email-1 data) email-2 (:email-2 data)] - (cond-> {} + (cond-> errors (and email-1 email-2 (not= email-1 email-2)) (assoc :email-2 {:message (tr "errors.email-invalid-confirmation")})))) diff --git a/frontend/src/app/main/ui/settings/password.cljs b/frontend/src/app/main/ui/settings/password.cljs index ce93a8af7..940e4fd8f 100644 --- a/frontend/src/app/main/ui/settings/password.cljs +++ b/frontend/src/app/main/ui/settings/password.cljs @@ -48,11 +48,11 @@ (s/def ::password-old ::us/not-empty-string) (defn- password-equality - [data] + [errors data] (let [password-1 (:password-1 data) password-2 (:password-2 data)] - (cond-> {} + (cond-> errors (and password-1 password-2 (not= password-1 password-2)) (assoc :password-2 {:message (tr "errors.password-invalid-confirmation")}) diff --git a/frontend/src/app/util/forms.cljs b/frontend/src/app/util/forms.cljs index 561eaa803..d29d11973 100644 --- a/frontend/src/app/util/forms.cljs +++ b/frontend/src/app/util/forms.cljs @@ -21,12 +21,16 @@ (and (empty? path) (list? pred) (= (first (last pred)) 'cljs.core/contains?)) - (let [path (conj path (last (last pred)))] - (assoc-in acc path {:code ::missing :type :builtin})) + (let [field (last (last pred)) + path (conj path field) + root (first via)] + (assoc-in acc path {:code :missing :type :builtin :root root :field field})) - (and (seq path) - (seq via)) - (assoc-in acc path {:code (last via) :type :builtin}) + (and (seq path) (seq via)) + (let [field (first path) + code (last via) + root (first via)] + (assoc-in acc path {:code code :type :builtin :root root :field field})) :else acc)) @@ -64,11 +68,12 @@ problems (when (= ::s/invalid cleaned) (::s/problems (s/explain-data spec (:data state)))) - errors (merge (reduce interpret-problem {} problems) - (reduce (fn [errors vf] - (merge errors (vf (:data state)))) - {} validators) - (:errors state))] + errors (reduce interpret-problem {} problems) + errors (reduce (fn [errors vf] + (merge errors (vf errors (:data state)))) + errors + validators) + errors (merge errors (:errors state))] (assoc state :errors errors diff --git a/frontend/translations/en.po b/frontend/translations/en.po index c0c7d771f..9f5933d53 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -767,6 +767,10 @@ msgstr "Looks like you are opening a file that has the feature '%s' enabled bug msgid "errors.email-already-exists" msgstr "Email already used" +#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs +msgid "errors.email-invalid" +msgstr "Enter a valid email please" + #: src/app/main/ui/auth/verify_token.cljs msgid "errors.email-already-validated" msgstr "Email already validated." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 4cc50f736..63e11b612 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -812,6 +812,10 @@ msgstr "Este fichero ya se ha usado con los Componentes V2 activados." msgid "errors.email-already-exists" msgstr "Este correo ya está en uso" +#: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs, src/app/main/ui/auth/recovery_request.cljs +msgid "errors.email-invalid" +msgstr "Por favor, escribe un email válido" + #: src/app/main/ui/auth/verify_token.cljs msgid "errors.email-already-validated" msgstr "Este correo ya está validado."