diff --git a/CHANGELOG.md b/CHANGELOG.md index d078ad39..85d2f888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixed - Taiwan flag is now shown on its own instead of in combination with China flag. +- On the registration page and other user forms, if something goes wrong, error messages are now shown to the user. ## Changed diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 3412bb08..f01254a8 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -51,7 +51,7 @@ class Users::RegistrationsController < Devise::RegistrationsController end def set_invitation - return unless invitation_token.present? + return if invitation_token.blank? @invitation = Family::Invitation.find_by(token: invitation_token) end diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index 257aba87..5536a889 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -17,6 +17,8 @@
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), class: 'form-body', method: :put, data: { turbo_method: :put, turbo: false }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> +
<%= f.label :email, class: 'label' do %> Email diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 707d9cee..4a32be9e 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -16,12 +16,23 @@
<% else %> -

Register now!

-

and take control over your location data.

+

Almost there!

<% end %> +

+ Only a few steps left until you get control over your location data! +

+
    +
  1. 1. Create your account
  2. +
  3. 2. Configure your mobile app
  4. +
  5. 3. Start tracking your location data securely
  6. +
  7. 4. ...
  8. +
  9. 5. You're beautiful!
  10. +
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), class: 'form-body', html: { data: { turbo: session[:dawarich_client] == 'ios' ? false : true } }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> <% if @invitation %> <%= f.hidden_field :invitation_token, value: params[:invitation_token] %> <% end %> @@ -32,7 +43,7 @@ <% end %> <%= f.email_field :email, autofocus: true, autocomplete: "email", readonly: @invitation.present?, - class: "input input-bordered #{@invitation ? 'input-disabled' : ''}" %> + class: "input input-bordered w-full #{@invitation ? 'input-disabled' : ''}" %>
@@ -42,7 +53,7 @@ <% if @minimum_password_length %> (<%= @minimum_password_length %> characters minimum) <% end %>
- <%= f.password_field :password, autocomplete: "new-password", class: 'input input-bordered' %> + <%= f.password_field :password, autocomplete: "new-password", class: 'input input-bordered w-full' %>
@@ -52,7 +63,7 @@ <% if @minimum_password_length %> (<%= @minimum_password_length %> characters minimum) <% end %>
- <%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'input input-bordered' %> + <%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'input input-bordered w-full' %>
<% if !DawarichSettings.self_hosted? %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index b471a5cf..633337c1 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -20,6 +20,8 @@
<%= form_for(resource, as: resource_name, url: session_path(resource_name), class: 'form-body', html: { data: { turbo: session[:dawarich_client] == 'ios' ? false : true } }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + <% if @invitation %> <%= hidden_field_tag :invitation_token, params[:invitation_token] %> <% end %> diff --git a/app/views/devise/shared/_error_messages.html.erb b/app/views/devise/shared/_error_messages.html.erb index cabfe307..2b2b4cfe 100644 --- a/app/views/devise/shared/_error_messages.html.erb +++ b/app/views/devise/shared/_error_messages.html.erb @@ -1,15 +1,20 @@ <% if resource.errors.any? %> -
-

- <%= I18n.t("errors.messages.not_saved", - count: resource.errors.count, - resource: resource.class.model_name.human.downcase) - %> -

- +
+ <%= icon 'circle-x' %> +
+
+

+ <%= I18n.t("errors.messages.not_saved", + count: resource.errors.count, + resource: resource.class.model_name.human.downcase) + %> +

+
    + <% resource.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+
<% end %> diff --git a/spec/requests/users/registrations_spec.rb b/spec/requests/users/registrations_spec.rb index efeac67c..6a5989ea 100644 --- a/spec/requests/users/registrations_spec.rb +++ b/spec/requests/users/registrations_spec.rb @@ -326,6 +326,70 @@ RSpec.describe 'Users::Registrations', type: :request do end end + describe 'Validation Error Handling' do + context 'when trying to register with an existing email' do + let!(:existing_user) { create(:user, email: 'existing@example.com') } + + it 'renders the registration form with error message' do + post user_registration_path, params: { + user: { + email: existing_user.email, + password: 'password123', + password_confirmation: 'password123' + } + } + + expect(response).to have_http_status(:unprocessable_content) + expect(response.body).to include('Email has already been taken') + expect(response.body).to include('error_explanation') + end + + it 'does not create a new user' do + expect do + post user_registration_path, params: { + user: { + email: existing_user.email, + password: 'password123', + password_confirmation: 'password123' + } + } + end.not_to change(User, :count) + end + end + + context 'when password is too short' do + it 'renders the registration form with error message' do + post user_registration_path, params: { + user: { + email: 'newuser@example.com', + password: 'short', + password_confirmation: 'short' + } + } + + expect(response).to have_http_status(:unprocessable_content) + expect(response.body).to include('Password is too short') + expect(response.body).to include('error_explanation') + end + end + + context 'when passwords do not match' do + it 'renders the registration form with error message' do + post user_registration_path, params: { + user: { + email: 'newuser@example.com', + password: 'password123', + password_confirmation: 'different123' + } + } + + expect(response).to have_http_status(:unprocessable_content) + expect(response.body).to include("Password confirmation doesn") + expect(response.body).to include('error_explanation') + end + end + end + describe 'UTM Parameter Tracking' do let(:utm_params) do {