Skip to content

Commit

Permalink
Add progress indicator to sign-up flow (#24545)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron committed Apr 16, 2023
1 parent 955ec25 commit e5c0b16
Show file tree
Hide file tree
Showing 76 changed files with 157 additions and 105 deletions.
19 changes: 3 additions & 16 deletions app/controllers/auth/setup_controller.rb
Expand Up @@ -10,30 +10,21 @@ class Auth::SetupController < ApplicationController

skip_before_action :require_functional!

def show
flash.now[:notice] = begin
if @user.pending?
I18n.t('devise.registrations.signed_up_but_pending')
else
I18n.t('devise.registrations.signed_up_but_unconfirmed')
end
end
end
def show; end

def update
# This allows updating the e-mail without entering a password as is required
# on the account settings page; however, we only allow this for accounts
# that were not confirmed yet

if @user.update(user_params)
redirect_to auth_setup_path, notice: I18n.t('devise.confirmations.send_instructions')
@user.resend_confirmation_instructions unless @user.confirmed?
redirect_to auth_setup_path, notice: I18n.t('auth.setup.new_confirmation_instructions_sent')
else
render :show
end
end

helper_method :missing_email?

private

def require_unconfirmed_or_pending!
Expand All @@ -51,8 +42,4 @@ def set_body_classes
def user_params
params.require(:user).permit(:email)
end

def missing_email?
truthy_param?(:missing_email)
end
end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Expand Up @@ -117,6 +117,10 @@ def fa_icon(icon, attributes = {})
content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end

def check_icon
content_tag(:svg, tag(:path, 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
end

def visibility_icon(status)
if status.public_visibility?
fa_icon('globe', title: I18n.t('statuses.visibilities.public'))
Expand Down
86 changes: 86 additions & 0 deletions app/javascript/styles/mastodon/forms.scss
Expand Up @@ -1112,3 +1112,89 @@ code {
white-space: nowrap;
}
}

.progress-tracker {
display: flex;
align-items: center;
padding-bottom: 30px;
margin-bottom: 30px;

li {
flex: 0 0 auto;
position: relative;
}

.separator {
height: 2px;
background: $ui-base-lighter-color;
flex: 1 1 auto;

&.completed {
background: $highlight-text-color;
}
}

.circle {
box-sizing: border-box;
position: relative;
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid $ui-base-lighter-color;
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: center;

svg {
width: 16px;
}
}

.label {
position: absolute;
font-size: 14px;
font-weight: 500;
color: $secondary-text-color;
padding-top: 10px;
text-align: center;
width: 100px;
left: 50%;
transform: translateX(-50%);
}

li:first-child .label {
left: auto;
inset-inline-start: 0;
text-align: start;
transform: none;
}

li:last-child .label {
left: auto;
inset-inline-end: 0;
text-align: end;
transform: none;
}

.active .circle {
border-color: $highlight-text-color;

&::before {
content: '';
width: 10px;
height: 10px;
border-radius: 50%;
background: $highlight-text-color;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}

.completed .circle {
border-color: $highlight-text-color;
background: $highlight-text-color;
}
}
8 changes: 6 additions & 2 deletions app/views/auth/registrations/new.html.haml
Expand Up @@ -5,6 +5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up }

= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { novalidate: false }) do |f|
= render 'auth/shared/progress', stage: 'details'

%h1.title= t('auth.sign_up.title', domain: site_hostname)
%p.lead= t('auth.sign_up.preamble')

Expand All @@ -18,17 +20,19 @@
.fields-group
= f.simple_fields_for :account do |ff|
= ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') }
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}"
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
= f.input :confirm_password, as: :string, placeholder: t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: t('simple_form.labels.defaults.password')), autocomplete: 'off' }, hint: false
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }

- if approved_registrations? && !@invite.present?
%p.lead= t('auth.sign_up.manual_review', domain: site_hostname)

.fields-group
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false


= hidden_field_tag :accept, params[:accept]
Expand Down
2 changes: 2 additions & 0 deletions app/views/auth/registrations/rules.html.haml
Expand Up @@ -5,6 +5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up }

.simple_form
= render 'auth/shared/progress', stage: 'rules'

%h1.title= t('auth.rules.title')
%p.lead= t('auth.rules.preamble', domain: site_hostname)

Expand Down
26 changes: 14 additions & 12 deletions app/views/auth/setup/show.html.haml
@@ -1,20 +1,22 @@
- content_for :page_title do
= t('auth.setup.title')

- if missing_email?
= simple_form_for(@user, url: auth_setup_path) do |f|
= render 'shared/error_messages', object: @user
= simple_form_for(@user, url: auth_setup_path) do |f|
= render 'auth/shared/progress', stage: 'confirm'

.fields-group
%p.hint= t('auth.setup.email_below_hint_html')
%h1.title= t('auth.setup.title')
%p.lead= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))

.fields-group
= f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
= render 'shared/error_messages', object: @user

.actions
= f.submit t('admin.accounts.change_email.label'), class: 'button'
- else
.simple_form
%p.hint= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))
%p.lead
%strong= t('auth.setup.link_not_received')
%p.lead= t('auth.setup.email_below_hint_html')

.fields-group
= f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }

.actions
= f.submit t('auth.resend_confirmation'), class: 'button'

.form-footer= render 'auth/shared/links'
2 changes: 1 addition & 1 deletion app/views/auth/shared/_links.html.haml
Expand Up @@ -14,5 +14,5 @@
- if controller_name != 'confirmations' && (!user_signed_in? || !current_user.confirmed? || current_user.unconfirmed_email.present?)
%li= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path

- if user_signed_in? && controller_name != 'setup'
- if user_signed_in?
%li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }
25 changes: 25 additions & 0 deletions app/views/auth/shared/_progress.html.haml
@@ -0,0 +1,25 @@
- progress_index = { rules: 0, details: 1, confirm: 2 }[stage.to_sym]

%ol.progress-tracker
%li{ class: progress_index.positive? ? 'completed' : 'active' }
.circle
- if progress_index.positive?
= check_icon
.label= t('auth.progress.rules')
%li.separator{ class: progress_index.positive? ? 'completed' : nil }
%li{ class: [progress_index > 1 && 'completed', progress_index == 1 && 'active'] }
.circle
- if progress_index > 1
= check_icon
.label= t('auth.progress.details')
%li.separator{ class: progress_index > 1 ? 'completed' : nil }
%li{ class: [progress_index > 2 && 'completed', progress_index == 2 && 'active'] }
.circle
- if progress_index > 2
= check_icon
.label= t('auth.progress.confirm')
- if approved_registrations?
%li.separator{ class: progress_index > 2 ? 'completed' : nil }
%li
.circle
.label= t('auth.progress.review')
22 changes: 15 additions & 7 deletions config/locales/en.yml
Expand Up @@ -125,8 +125,8 @@ en:
removed_header_msg: Successfully removed %{username}'s header image
resend_confirmation:
already_confirmed: This user is already confirmed
send: Resend confirmation email
success: Confirmation email successfully sent!
send: Resend confirmation link
success: Confirmation link successfully sent!
reset: Reset
reset_password: Reset password
resubscribe: Resubscribe
Expand Down Expand Up @@ -988,7 +988,7 @@ en:
prefix_invited_by_user: "@%{name} invites you to join this server of Mastodon!"
prefix_sign_up: Sign up on Mastodon today!
suffix: With an account, you will be able to follow people, post updates and exchange messages with users from any Mastodon server and more!
didnt_get_confirmation: Didn't receive confirmation instructions?
didnt_get_confirmation: Didn't receive a confirmation link?
dont_have_your_security_key: Don't have your security key?
forgot_password: Forgot your password?
invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.
Expand All @@ -1001,12 +1001,17 @@ en:
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in with
privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
progress:
confirm: Confirm e-mail
details: Your details
review: Our review
rules: Accept rules
providers:
cas: CAS
saml: SAML
register: Sign up
registration_closed: "%{instance} is not accepting new members"
resend_confirmation: Resend confirmation instructions
resend_confirmation: Resend confirmation link
reset_password: Reset password
rules:
accept: Accept
Expand All @@ -1016,13 +1021,16 @@ en:
security: Security
set_new_password: Set new password
setup:
email_below_hint_html: If the below e-mail address is incorrect, you can change it here and receive a new confirmation e-mail.
email_settings_hint_html: The confirmation e-mail was sent to %{email}. If that e-mail address is not correct, you can change it in account settings.
title: Setup
email_below_hint_html: Check your spam folder, or request another one. You can correct your e-mail address if it's wrong.
email_settings_hint_html: Click the link we sent you to verify %{email}. We'll wait right here.
link_not_received: Didn't get a link?
new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
title: Check your inbox
sign_in:
preamble_html: Sign in with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here.
title: Sign in to %{domain}
sign_up:
manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
title: Let's get you set up on %{domain}.
status:
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.an.yml
Expand Up @@ -59,7 +59,6 @@ an:
setting_show_application: L'aplicación que utiliza vusté pa publicar publicacions s'amostrará en a vista detallada d'as suyas publicacions
setting_use_blurhash: Los gradientes se basan en as colors d'as imachens amagadas pero fendo borrosos los detalles
setting_use_pending_items: Amagar nuevos estaus dezaga d'un clic en cuenta de desplazar automaticament lo feed
username: Lo tuyo nombre d'usuario será solo en %{domain}
whole_word: Quan la parola clau u frase ye nomás alfanumerica, nomás será aplicau si concuerda con tota la parola
domain_allow:
domain: Este dominio podrá obtener datos d'este servidor y los datos dentrants serán procesaus y archivados
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.ar.yml
Expand Up @@ -59,7 +59,6 @@ ar:
setting_show_application: سيُعرَض اسم التطبيق الذي تستخدمه عند النشر في العرض المفصّل لمنشوراتك
setting_use_blurhash: الألوان التدرّجية مبنية على ألوان المرئيات المخفية ولكنها تحجب كافة التفاصيل
setting_use_pending_items: إخفاء تحديثات الخط وراء نقرة بدلًا مِن التمرير التلقائي للتدفق
username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}
whole_word: إذا كانت الكلمة أو العبارة مكونة من أرقام وحروف فقط سوف يتم تطبيقها فقط عند مطابقة الكلمة ككل
domain_allow:
domain: سيكون بإمكان هذا النطاق جلب البيانات من هذا الخادم ومعالجة وتخزين البيانات الواردة منه
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.ast.yml
Expand Up @@ -35,7 +35,6 @@ ast:
setting_noindex: Afeuta al perfil públicu ya a les páxines de los artículos
setting_show_application: L'aplicación qu'uses pa espublizar apaez na vista detallada de los tos artículos
setting_use_blurhash: Los dilíos básense nos colores del conteníu multimedia anubríu mas desenfonca los detalles
username: 'El nome d''usuariu va ser únicu en: %{domain}'
featured_tag:
name: 'Equí tán dalgunes de les etiquetes qu''usesti apocayá:'
form_admin_settings:
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.be.yml
Expand Up @@ -59,7 +59,6 @@ be:
setting_show_application: Праграма, праз якую вы ствараеце допісы, будзе паказвацца ў падрабязнасцях пра допісы
setting_use_blurhash: Градыенты заснаваны на колерах схаваных выяў, але размываюць дэталі
setting_use_pending_items: Схаваць абнаўленні стужкі за клікам замест аўтаматычнага пракручвання стужкі
username: Ваша імя карыстальніка будзе ўнікальным на %{domain}
whole_word: Калі ключавое слова ці фраза складаецца толькі з літар і лічбаў, яно будзе ўжытае толькі калі супадае з усім словам
domain_allow:
domain: Гэты дамен зможа атрымліваць даныя з гэтага сервера. Даныя з гэтага дамену будуць апрацаваныя ды захаваныя
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.bg.yml
Expand Up @@ -59,7 +59,6 @@ bg:
setting_show_application: Приложението, което ползвате за публикуване, ще се показва в подробностите на публикацията ви
setting_use_blurhash: Преливането е въз основа на цветовете на скритите визуализации, но се замъгляват подробностите
setting_use_pending_items: Да се показват обновявания на часовата ос само след щракване вместо автоматично превъртане на инфоканала
username: Вашето потребителско име ще е неповторимо в %{domain}
whole_word: Ако ключовата дума или фраза е само буквеноцифрена, то ще се приложи само, ако съвпадне с цялата дума
domain_allow:
domain: Домейнът ще може да извлича данни от този сървър и входящите данни от него ще се обработят и съхранят
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.ca.yml
Expand Up @@ -59,7 +59,6 @@ ca:
setting_show_application: L'aplicació que fas servir per a publicar es mostrarà a la vista detallada dels teus tuts
setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls
setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament
username: El teu nom d'usuari serà únic a %{domain}
whole_word: Quan la paraula clau o la frase sigui només alfanumèrica, s'aplicarà si coincideix amb la paraula sencera
domain_allow:
domain: Aquest domini podrà obtenir dades d’aquest servidor i les dades entrants d’aquests seran processades i emmagatzemades
Expand Down
1 change: 0 additions & 1 deletion config/locales/simple_form.ckb.yml
Expand Up @@ -51,7 +51,6 @@ ckb:
setting_show_application: بەرنامەیەک کە بە یارمەتیت توت دەکەیت، لە دیمەنی وردی توتەکان پیشان دەدرێت
setting_use_blurhash: سێبەرەکان لە سەر بنەمای ڕەنگەکانی بەکارهاتوو لە وێنە داشاراوەکان دروست دەبن بەڵام وردەزانیاری وێنە تێیدا ڕوون نییە
setting_use_pending_items: لەجیاتی ئەوەی بە خۆکارانە کێشان هەبێت لە نووسراوەکان بە کرتەیەک بەڕۆژبوونی پێرستی نووسراوەکان بشارەوە
username: ناوی بەکارهێنەری ئێوە لەسەر %{domain} یەکتا دەبێت
whole_word: کاتێک کلیل‌وشە بریتییە لە ژمارە و پیت، تنەها کاتێک پەیدا دەبێت کە لەگەڵ گشتی وشە لە نێو دەقەکە هاوئاهەنگ بێت، نە تەنها لەگەڵ بەشێک لە وشە
domain_allow:
domain: ئەم دۆمەینە دەتوانێت دراوە لە ئەم ڕاژە وەربگرێت و دراوەی ئەم دۆمەینە لێرە ڕێکدەخرین و پاشکەوت دەکرێن
Expand Down

0 comments on commit e5c0b16

Please sign in to comment.