Improve the way users give us feedback

This commit is contained in:
Marina López 2025-08-29 14:07:55 +02:00 committed by Andrey Antukh
parent a32f44a62c
commit 854ad5bb4d
10 changed files with 261 additions and 76 deletions

View File

@ -197,7 +197,14 @@
:settings-subscription
:settings-access-tokens
:settings-notifications)
[:? [:& settings-page {:route route}]]
(let [params (get params :query)
type (some-> params :type)
report-id (some-> params :report-id)
url-error (some-> params :url-error)]
[:? [:& settings-page {:route route
:type type
:report-id report-id
:url-error url-error}]])
:debug-icons-preview
(when *assert*

View File

@ -34,7 +34,7 @@
[:h1 {:data-testid "account-title"} (tr "dashboard.your-account-title")]]])
(mf/defc settings
[{:keys [route] :as props}]
[{:keys [route type report-id url-error]}]
(let [section (get-in route [:data :name])
profile (mf/deref refs/profile)]
@ -60,7 +60,9 @@
[:& profile-page]
:settings-feedback
[:& feedback-page]
[:& feedback-page {:type type
:report-id report-id
:url-error url-error}]
:settings-password
[:& password-page]

View File

@ -16,20 +16,37 @@
[app.main.ui.components.forms :as fm]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.webapi :as wapi]
[beicon.v2.core :as rx]
[rumext.v2 :as mf]))
(def ^:private schema:feedback-form
(defn schema:feedback-form [url-error]
[:map {:title "FeedbackForm"}
[:subject [::sm/text {:max 250}]]
[:content [::sm/text {:max 5000}]]])
[:type [:string {:max 250}]]
[:content [::sm/text {:max 5000}]]
[:penpot-link [::sm/text {:max 2048 :value (or url-error "") :optional true}]]])
(mf/defc feedback-form
{::mf/private true}
[]
(let [profile (mf/deref refs/profile)
form (fm/use-form :schema schema:feedback-form)
loading (mf/use-state false)
[{:keys [report type url-error]}]
(let [profile (mf/deref refs/profile)
initial (mf/with-memo [url-error]
{:subject ""
:type (or type "")
:content ""
:penpot-link url-error})
form (fm/use-form :schema (schema:feedback-form url-error) :initial initial)
loading (mf/use-state false)
report (wapi/create-blob report "text/plain")
report-uri (wapi/create-uri report)
on-download
(mf/use-fn
(mf/deps report)
(fn [event]
(dom/prevent-default event)
(dom/trigger-download-uri "report" "text/plain" report-uri)))
on-succes
(mf/use-fn
@ -62,19 +79,41 @@
:form form}
;; --- Feedback section
[:h2 {:class (stl/css :field-title)} (tr "feedback.title")]
[:p {:class (stl/css :field-text)} (tr "feedback.subtitle")]
[:h2 {:class (stl/css :field-title :feedback-title)} (tr "feedback.title-contact-us")]
[:p {:class (stl/css :field-text :feedback-title)} (tr "feedback.subtitle")]
[:div {:class (stl/css :fields-row)}
[:& fm/input {:label (tr "feedback.subject")
:name :subject
:show-success? true}]]
[:div {:class (stl/css :fields-row)}
[:label {:class (stl/css :field-label)} (tr "feedback.type")]
[:& fm/select {:label (tr "feedback.type")
:name :type
:options [{:label (tr "feedback.type.idea") :value "idea"}
{:label (tr "feedback.type.issue") :value "issue"}
{:label (tr "feedback.type.doubt") :value "doubt"}]}]]
[:div {:class (stl/css :fields-row :description)}
[:& fm/textarea
{:label (tr "feedback.description")
{:class (stl/css :feedback-description)
:label (tr "feedback.description")
:name :content
:placeholder (tr "feedback.description-placeholder")
:rows 5}]]
[:div {:class (stl/css :fields-row)}
[:p {:class (stl/css :field-text)} (tr "feedback.penpot.link")]
[:& fm/input {:label ""
:name :penpot-link
:placeholder "https://penpot.app/"
:show-success? true}]
(when report
[:a {:class (stl/css :link :download-button) :on-click on-download}
(tr "labels.download" "report.txt")])]
[:> fm/submit-button*
{:label (if @loading (tr "labels.sending") (tr "labels.send"))
:class (stl/css :feedback-button-link)
@ -82,30 +121,28 @@
[:hr]
[:h2 {:class (stl/css :field-title)} (tr "feedback.discourse-title")]
[:p {:class (stl/css :field-text)} (tr "feedback.discourse-subtitle1")]
[:h2 {:class (stl/css :feedback-title)} (tr "feedback.other-ways-contact")]
[:a
{:class (stl/css :feedback-button-link)
:href "https://community.penpot.app"
:target "_blank"}
(tr "feedback.discourse-go-to")]
[:hr]
[:h2 {:class (stl/css :field-title)} (tr "feedback.twitter-title")]
[:p {:class (stl/css :field-text)} (tr "feedback.twitter-subtitle1")]
[:a {:class (stl/css :link)
:href "https://community.penpot.app"
:target "_blank"}
(tr "feedback.discourse-title")]
[:p {:class (stl/css :field-text :bottom-margin)} (tr "feedback.discourse-subtitle1")]
[:a
{:class (stl/css :feedback-button-link)
:href "https://twitter.com/penpotapp"
:target "_blank"}
(tr "feedback.twitter-go-to")]]))
[:a {:class (stl/css :link)
:href "https://x.com/penpotapp"
:target "_blank"}
(tr "feedback.twitter-title")]
[:p {:class (stl/css :field-text)} (tr "feedback.twitter-subtitle1")]]))
(mf/defc feedback-page
[]
[{:keys [type report-id url-error]}]
(mf/with-effect []
(dom/set-html-title (tr "title.settings.feedback")))
[:div {:class (stl/css :dashboard-settings)}
[:div {:class (stl/css :form-container)}
[:& feedback-form]]])
(let [report (.getItem js/localStorage report-id)]
[:div {:class (stl/css :dashboard-settings)}
[:div {:class (stl/css :form-container)}
[:& feedback-form {:report report
:type type
:url-error url-error}]]]))

View File

@ -6,24 +6,74 @@
@use "common/refactor/common-refactor" as *;
@use "./profile";
@use "../ds/typography.scss" as t;
@use "../ds/_borders.scss" as b;
@use "../ds/_sizes.scss" as *;
@use "../ds/_utils.scss" as *;
@use "../ds/spacing.scss" as *;
.feedback-form {
textarea {
border-radius: $br-8;
padding: $br-12;
.fields-row {
margin-block-end: $sz-32;
}
.feedback-description {
@include t.use-typography("body-medium");
border-radius: b.$br-8;
padding: var(--sp-m);
background-color: var(--color-background-tertiary);
color: var(--color-foreground-primary);
border: none;
::placeholder {
color: var(--color-background-disabled);
color: var(--input-placeholder-color);
}
&:focus {
outline: $s-1 solid var(--color-accent-primary);
outline: b.$b-1 solid var(--color-accent-primary);
}
}
}
.feedback-button-link {
@extend .button-primary;
.field-label {
@include t.use-typography("headline-small");
block-size: $sz-32;
color: var(--color-foreground-primary);
margin-block-end: var(--sp-l);
}
.feedback-button-link {
@extend .button-primary;
margin-block-end: px2rem(72);
}
.feedback-title {
margin-block-end: var(--sp-xxxl);
}
.field-text {
@include t.use-typography("body-medium");
}
.bottom-margin {
margin-block-end: var(--sp-xxxl);
}
.link {
@include t.use-typography("headline-small");
color: var(--color-accent-tertiary);
margin-block-end: var(--sp-s);
}
.download-button {
@include t.use-typography("body-small");
color: var(--color-foreground-primary);
text-transform: lowercase;
border: b.$b-1 solid var(--color-background-quaternary);
margin-block-start: var(--sp-s);
padding: var(--sp-s);
border-radius: b.$br-8;
block-size: $sz-32;
display: inline-block;
min-inline-size: $sz-160;
text-align: center;
}
}

View File

@ -11,7 +11,7 @@
width: 100%;
justify-content: center;
align-items: center;
a:not(.button-primary) {
a:not(.button-primary):not(.link) {
color: var(--color-foreground-secondary);
}
}

View File

@ -133,7 +133,7 @@
:settings-item true)
:on-click go-settings-feedback}
feedback-icon
[:span {:class (stl/css :element-title)} (tr "labels.give-feedback")]])]]]))
[:span {:class (stl/css :element-title)} (tr "labels.contact-us")]])]]]))
(mf/defc sidebar
{::mf/wrap [mf/memo]

View File

@ -22,6 +22,7 @@
[app.main.ui.auth.recovery-request :refer [recovery-request-page recovery-sent-page]]
[app.main.ui.auth.register :as register]
[app.main.ui.dashboard.sidebar :refer [sidebar*]]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg*]]
[app.main.ui.icons :as deprecated-icon]
@ -351,7 +352,16 @@
(mf/defc internal-error*
[{:keys [on-reset report] :as props}]
(let [report-uri (mf/use-ref nil)
on-reset (or on-reset #(st/emit! (rt/assign-exception nil)))
on-reset (or on-reset #(st/emit! (rt/assign-exception nil)))
support-contact-click
(mf/use-fn
(fn []
(let [report-id (str "report-" (random-uuid))]
(.setItem js/localStorage report-id report)
(st/emit! (rt/nav :settings-feedback {:type "issue"
:report-id report-id
:url-error (rt/get-current-href)})))))
on-download
(mf/use-fn
@ -370,11 +380,23 @@
[:> error-container* {}
[:div {:class (stl/css :main-message)} (tr "labels.internal-error.main-message")]
[:div {:class (stl/css :desc-message)} (tr "labels.internal-error.desc-message")]
[:div {:class (stl/css :desc-message)}
[:p {:class (stl/css :desc-text)} (tr "labels.internal-error.desc-message-first")]
[:p {:class (stl/css :desc-text)} (tr "labels.internal-error.desc-message-second")]]
(when (some? report)
[:a {:on-click on-download} "Download report.txt"])
[:div {:class (stl/css :sign-info)}
[:button {:on-click on-reset} (tr "labels.retry")]]]))
[:a {:class (stl/css :download-link) :on-click on-download} (tr "labels.download" "report.txt")])
[:div {:class (stl/css :buttons-container)}
[:> button* {:variant "secondary"
:type "button"
:class (stl/css :support-btn)
:on-click support-contact-click} (tr "labels.contact-support")]
[:> button* {:variant "primary"
:type "button"
:class (stl/css :retry-btn)
:on-click on-reset} (tr "labels.retry")]]]))
(defn- load-info
"Load exception page info"

View File

@ -5,6 +5,7 @@
// Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated;
@use "./ds/typography.scss" as t;
.exception-layout {
width: 100%;
@ -133,15 +134,27 @@
}
.main-message {
@include deprecated.bigTitleTipography;
@include t.use-typography("title-large");
color: var(--color-foreground-primary);
}
.desc-message {
@include deprecated.bigTitleTipography;
@include t.use-typography("title-large");
color: var(--color-foreground-secondary);
}
.desc-text {
@include t.use-typography("title-large");
color: var(--color-foreground-secondary);
margin-block-end: 0;
}
.download-link {
@include t.use-typography("code-font");
color: var(--color-foreground-primary);
text-transform: lowercase;
}
.sign-info {
text-align: center;
@ -333,5 +346,13 @@
.login-container {
width: 100%;
background-color: red;
background-color: var(--color-background-error);
}
.buttons-container {
display: flex;
.retry-btn {
margin-inline-start: var(--sp-xxl);
}
}

View File

@ -1559,9 +1559,8 @@ msgstr "Old password is incorrect"
msgid "feedback.description"
msgstr "Description"
#: src/app/main/ui/settings/feedback.cljs:92
msgid "feedback.discourse-go-to"
msgstr "Go to Penpot forum"
msgid "feedback.description-placeholder"
msgstr "Please describe the reason of your feedback"
#: src/app/main/ui/settings/feedback.cljs:86
msgid "feedback.discourse-subtitle1"
@ -1569,6 +1568,9 @@ msgstr ""
"We're happy to have you here. If you need help, please search before you "
"post."
msgid "feedback.other-ways-contact"
msgstr "Other ways to contact us"
#: src/app/main/ui/settings/feedback.cljs:85
msgid "feedback.discourse-title"
msgstr "Penpot community"
@ -1577,6 +1579,21 @@ msgstr "Penpot community"
msgid "feedback.subject"
msgstr "Subject"
msgid "feedback.type"
msgstr "Type"
msgid "feedback.type.idea"
msgstr "Idea"
msgid "feedback.type.issue"
msgstr "Issue"
msgid "feedback.type.doubt"
msgstr "Doubt"
msgid "feedback.penpot.link"
msgstr "If the feedback is something related with a file or a project, add the penpot link in here:"
#: src/app/main/ui/settings/feedback.cljs:66
msgid "feedback.subtitle"
msgstr ""
@ -1584,12 +1601,8 @@ msgstr ""
"idea or a doubt. A member of our team will respond as soon as possible."
#: src/app/main/ui/settings/feedback.cljs:65
msgid "feedback.title"
msgstr "Email"
#: src/app/main/ui/settings/feedback.cljs:102
msgid "feedback.twitter-go-to"
msgstr "Go to X"
msgid "feedback.title-contact-us"
msgstr "Contact us"
#: src/app/main/ui/settings/feedback.cljs:96
msgid "feedback.twitter-subtitle1"
@ -2217,6 +2230,9 @@ msgstr "Github repository"
msgid "labels.give-feedback"
msgstr "Give feedback"
msgid "labels.contact-us"
msgstr "Contact us"
#: src/app/main/ui/auth/recovery_request.cljs:104, src/app/main/ui/auth/register.cljs:359, src/app/main/ui/static.cljs:170, src/app/main/ui/viewer/login.cljs:111
msgid "labels.go-back"
msgstr "Go back"
@ -2254,10 +2270,11 @@ msgid "labels.installed-fonts"
msgstr "Installed fonts"
#: src/app/main/ui/static.cljs:373
msgid "labels.internal-error.desc-message"
msgstr ""
"Something bad happened. Please retry the operation and if the problem "
"persists, contact support."
msgid "labels.internal-error.desc-message-first"
msgstr "Something bad happened."
msgid "labels.internal-error.desc-message-second"
msgstr "You can retry the operation or contact support to report the error."
#: src/app/main/ui/static.cljs:372
msgid "labels.internal-error.main-message"
@ -2525,6 +2542,12 @@ msgstr "Restore"
msgid "labels.retry"
msgstr "Retry"
msgid "labels.download"
msgstr "Download %s"
msgid "labels.contact-support"
msgstr "Contact support"
#: src/app/main/ui/dashboard/team.cljs:513, src/app/main/ui/dashboard/team.cljs:945
msgid "labels.role"
msgstr "Role"

View File

@ -1556,9 +1556,8 @@ msgstr "La contraseña anterior no es correcta"
msgid "feedback.description"
msgstr "Descripción"
#: src/app/main/ui/settings/feedback.cljs:92
msgid "feedback.discourse-go-to"
msgstr "Ir al foro de Penpot"
msgid "feedback.description-placeholder"
msgstr "Describe el motivo de tu comentario"
#: src/app/main/ui/settings/feedback.cljs:86
msgid "feedback.discourse-subtitle1"
@ -1566,6 +1565,9 @@ msgstr ""
"Estamos encantados de tenerte por aquí. Si necesitas ayuda, busca, escribe "
"o pregunta lo que necesites."
msgid "feedback.other-ways-contact"
msgstr "Otras formas de contactarnos"
#: src/app/main/ui/settings/feedback.cljs:85
msgid "feedback.discourse-title"
msgstr "Comunidad de Penpot"
@ -1574,6 +1576,21 @@ msgstr "Comunidad de Penpot"
msgid "feedback.subject"
msgstr "Asunto"
msgid "feedback.type"
msgstr "Tipo"
msgid "feedback.type.idea"
msgstr "Idea"
msgid "feedback.type.issue"
msgstr "Problema"
msgid "feedback.type.doubt"
msgstr "Duda"
msgid "feedback.penpot.link"
msgstr "Si el comentario está relacionado con un archivo o un proyecto, añade aquí el enlace de Penpot:"
#: src/app/main/ui/settings/feedback.cljs:66
msgid "feedback.subtitle"
msgstr ""
@ -1582,12 +1599,8 @@ msgstr ""
"pronto como sea posible."
#: src/app/main/ui/settings/feedback.cljs:65
msgid "feedback.title"
msgstr "Correo electrónico"
#: src/app/main/ui/settings/feedback.cljs:102
msgid "feedback.twitter-go-to"
msgstr "Ir a X"
msgid "feedback.title-contact-us"
msgstr "Contáctanos"
#: src/app/main/ui/settings/feedback.cljs:96
msgid "feedback.twitter-subtitle1"
@ -2195,6 +2208,9 @@ msgstr "Repositorio de Github"
msgid "labels.give-feedback"
msgstr "Danos tu opinión"
msgid "labels.contact-us"
msgstr "Contáctanos"
#: src/app/main/ui/auth/recovery_request.cljs:104, src/app/main/ui/auth/register.cljs:359, src/app/main/ui/static.cljs:170, src/app/main/ui/viewer/login.cljs:111
msgid "labels.go-back"
msgstr "Volver"
@ -2232,10 +2248,11 @@ msgid "labels.installed-fonts"
msgstr "Fuentes instaladas"
#: src/app/main/ui/static.cljs:373
msgid "labels.internal-error.desc-message"
msgstr ""
"Ha ocurrido algo extraño. Por favor, reintenta la operación, y si el "
"problema persiste, contacta con el servicio técnico."
msgid "labels.internal-error.desc-message-first"
msgstr "Ha ocurrido algo extraño."
msgid "labels.internal-error.desc-message-second"
msgstr "Puedes reintentar la operación o contacta con soporte para reportar el error."
#: src/app/main/ui/static.cljs:372
msgid "labels.internal-error.main-message"
@ -2495,6 +2512,12 @@ msgstr "Restaurar"
msgid "labels.retry"
msgstr "Reintentar"
msgid "labels.download"
msgstr "Descargar %s"
msgid "labels.contact-support"
msgstr "Contacta con soporte"
#: src/app/main/ui/dashboard/team.cljs:513, src/app/main/ui/dashboard/team.cljs:945
msgid "labels.role"
msgstr "Rol"