diff --git a/app/assets/images/user-access.svg b/app/assets/images/user-access.svg index 7482ff66a03..6f9fff51b63 100644 --- a/app/assets/images/user-access.svg +++ b/app/assets/images/user-access.svg @@ -73,10 +73,7 @@ - - - - + @@ -154,5 +151,9 @@ + + + + diff --git a/app/assets/stylesheets/components/_nav.scss b/app/assets/stylesheets/components/_nav.scss index 7fdb70533b2..848513c2945 100644 --- a/app/assets/stylesheets/components/_nav.scss +++ b/app/assets/stylesheets/components/_nav.scss @@ -21,3 +21,32 @@ img { height: 17px; } } } + +.sidenav-mobile { + @include at-media('desktop') { + display: none; + } + + .usa-nav__close { + @include add-background-svg('close-blue-60v-alt'); + @include u-square(6); + background-position: center center; + background-repeat: no-repeat; + } +} + +.sidenav { + display: none; + + @include at-media('desktop') { + display: block; + } +} + +.authnav-greeting { + display: none; + + @include at-media('desktop') { + display: block; + } +} diff --git a/app/assets/stylesheets/components/_profile-section.scss b/app/assets/stylesheets/components/_profile-section.scss index fb84149b984..26400ae795b 100644 --- a/app/assets/stylesheets/components/_profile-section.scss +++ b/app/assets/stylesheets/components/_profile-section.scss @@ -1,9 +1,9 @@ .profile-info-box { border: 0; - border-bottom: $border-width solid $border-color; border-radius: 0; margin-bottom: 0; overflow: hidden; + padding: $space-3; .bg-lightest-blue img { margin-top: -2px; @@ -11,8 +11,27 @@ } } -@media #{$breakpoint-sm} { +@include at-media('mobile') { .profile-info-box { + border-radius: $border-radius-md; + margin-bottom: $space-3; + } +} + +.events-info-box { + border: $border-width solid $border-color; + border-radius: 0; + margin-bottom: 0; + overflow: hidden; + + .bg-lightest-blue img { + margin-top: -2px; + vertical-align: middle; + } +} + +@include at-media('mobile') { + .events-info-box { border: $border-width solid $border-color; border-radius: $border-radius-md; margin-bottom: $space-3; diff --git a/app/assets/stylesheets/components/_util.scss b/app/assets/stylesheets/components/_util.scss index 40e95b730eb..b215d5fb4ff 100644 --- a/app/assets/stylesheets/components/_util.scss +++ b/app/assets/stylesheets/components/_util.scss @@ -69,7 +69,6 @@ // Temporary Classes for Overriding during design system migration - .border-top { border-top: 1px solid $border-color; } diff --git a/app/controllers/accounts/connected_accounts_controller.rb b/app/controllers/accounts/connected_accounts_controller.rb new file mode 100644 index 00000000000..6c2a5db033f --- /dev/null +++ b/app/controllers/accounts/connected_accounts_controller.rb @@ -0,0 +1,17 @@ +module Accounts + class ConnectedAccountsController < ApplicationController + include RememberDeviceConcern + before_action :confirm_two_factor_authenticated + + layout 'account_side_nav' + + def show + @view_model = AccountShow.new( + decrypted_pii: nil, + personal_key: flash[:personal_key], + decorated_user: current_user.decorate, + locked_for_session: pii_locked_for_session?(current_user), + ) + end + end +end diff --git a/app/controllers/accounts/history_controller.rb b/app/controllers/accounts/history_controller.rb new file mode 100644 index 00000000000..ff60ea139bf --- /dev/null +++ b/app/controllers/accounts/history_controller.rb @@ -0,0 +1,17 @@ +module Accounts + class HistoryController < ApplicationController + include RememberDeviceConcern + before_action :confirm_two_factor_authenticated + + layout 'account_side_nav' + + def show + @view_model = AccountShow.new( + decrypted_pii: nil, + personal_key: flash[:personal_key], + decorated_user: current_user.decorate, + locked_for_session: pii_locked_for_session?(current_user), + ) + end + end +end diff --git a/app/controllers/accounts/two_factor_authentication_controller.rb b/app/controllers/accounts/two_factor_authentication_controller.rb new file mode 100644 index 00000000000..ba93183a373 --- /dev/null +++ b/app/controllers/accounts/two_factor_authentication_controller.rb @@ -0,0 +1,18 @@ +module Accounts + class TwoFactorAuthenticationController < ApplicationController + include RememberDeviceConcern + before_action :confirm_two_factor_authenticated + + layout 'account_side_nav' + + def show + session[:account_redirect_path] = account_two_factor_authentication_path + @view_model = AccountShow.new( + decrypted_pii: nil, + personal_key: flash[:personal_key], + decorated_user: current_user.decorate, + locked_for_session: pii_locked_for_session?(current_user), + ) + end + end +end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index e60f20caeee..e327e8dbf43 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -2,10 +2,11 @@ class AccountsController < ApplicationController include RememberDeviceConcern before_action :confirm_two_factor_authenticated - layout 'card_wide' + layout 'account_side_nav' def show analytics.track_event(Analytics::ACCOUNT_VISIT) + session[:account_redirect_path] = account_path cacher = Pii::Cacher.new(current_user, user_session) @view_model = AccountShow.new( decrypted_pii: cacher.fetch, diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f2d8f9a89b5..ebb9b160361 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -174,7 +174,7 @@ def after_mfa_setup_path elsif user_needs_to_reactivate_account? reactivate_account_url else - after_sign_in_path_for(current_user) + session[:account_redirect_path] || after_sign_in_path_for(current_user) end end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index ec170846ab5..b57e8649a23 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -1,7 +1,7 @@ class EventsController < ApplicationController include RememberDeviceConcern before_action :confirm_two_factor_authenticated - layout 'card_wide' + layout 'no_card' EVENTS_PAGE_SIZE = 25 diff --git a/app/controllers/test/telephony_controller.rb b/app/controllers/test/telephony_controller.rb index 01b6264b6a3..3ed7732836c 100644 --- a/app/controllers/test/telephony_controller.rb +++ b/app/controllers/test/telephony_controller.rb @@ -1,6 +1,6 @@ module Test class TelephonyController < ApplicationController - layout 'card_wide' + layout 'no_card' before_action :render_not_found_in_production diff --git a/app/controllers/users/backup_code_setup_controller.rb b/app/controllers/users/backup_code_setup_controller.rb index 5f2da6fef95..65840b4ba61 100644 --- a/app/controllers/users/backup_code_setup_controller.rb +++ b/app/controllers/users/backup_code_setup_controller.rb @@ -45,7 +45,7 @@ def delete current_user.backup_code_configurations.destroy_all flash[:success] = t('notices.backup_codes_deleted') revoke_remember_device(current_user) - redirect_to account_url + redirect_to account_two_factor_authentication_path end private diff --git a/app/controllers/users/piv_cac_authentication_setup_controller.rb b/app/controllers/users/piv_cac_authentication_setup_controller.rb index 47b626f432d..b30380865c0 100644 --- a/app/controllers/users/piv_cac_authentication_setup_controller.rb +++ b/app/controllers/users/piv_cac_authentication_setup_controller.rb @@ -28,7 +28,7 @@ def delete clear_piv_cac_information create_user_event(:piv_cac_disabled) flash[:success] = t('notices.piv_cac_disabled') - redirect_to account_url + redirect_to account_two_factor_authentication_path end def submit_new_piv_cac @@ -118,8 +118,8 @@ def process_invalid_submission end def authorize_piv_cac_disable - return redirect_to account_url unless piv_cac_enabled? && - MfaPolicy.new(current_user).multiple_factors_enabled? + return if piv_cac_enabled? && MfaPolicy.new(current_user).multiple_factors_enabled? + redirect_to account_two_factor_authentication_path end def good_nickname @@ -128,7 +128,8 @@ def good_nickname end def cap_piv_cac_count - redirect_to account_url if Figaro.env.max_piv_cac_per_account.to_i <= current_cac_count + return unless Figaro.env.max_piv_cac_per_account.to_i <= current_cac_count + redirect_to account_two_factor_authentication_path end def current_cac_count diff --git a/app/controllers/users/service_provider_revoke_controller.rb b/app/controllers/users/service_provider_revoke_controller.rb index 58d2bf0bb9f..0be4ef9c891 100644 --- a/app/controllers/users/service_provider_revoke_controller.rb +++ b/app/controllers/users/service_provider_revoke_controller.rb @@ -3,7 +3,7 @@ class ServiceProviderRevokeController < ApplicationController before_action :confirm_two_factor_authenticated rescue_from ActiveRecord::RecordNotFound do - redirect_to account_url + redirect_to account_connected_accounts_path end def show @@ -19,7 +19,7 @@ def destroy RevokeServiceProviderConsent.new(identity).call analytics.track_event(Analytics::SP_REVOKE_CONSENT_REVOKED, issuer: @service_provider.issuer) - redirect_to account_url + redirect_to account_connected_accounts_path end private diff --git a/app/controllers/users/totp_setup_controller.rb b/app/controllers/users/totp_setup_controller.rb index fdfb0f004f3..83f3ad5be95 100644 --- a/app/controllers/users/totp_setup_controller.rb +++ b/app/controllers/users/totp_setup_controller.rb @@ -34,7 +34,7 @@ def confirm def disable process_successful_disable if MfaPolicy.new(current_user).multiple_factors_enabled? - redirect_to account_url + redirect_to account_two_factor_authentication_path end private @@ -124,7 +124,8 @@ def new_totp_secret end def cap_auth_app_count - redirect_to account_url if Figaro.env.max_auth_apps_per_account.to_i <= current_auth_app_count + return unless Figaro.env.max_auth_apps_per_account.to_i <= current_auth_app_count + redirect_to account_two_factor_authentication_path end def current_auth_app_count diff --git a/app/controllers/users/webauthn_setup_controller.rb b/app/controllers/users/webauthn_setup_controller.rb index 62c7d409c03..ee2abd4fdee 100644 --- a/app/controllers/users/webauthn_setup_controller.rb +++ b/app/controllers/users/webauthn_setup_controller.rb @@ -34,7 +34,7 @@ def delete else handle_failed_delete end - redirect_to account_url + redirect_to account_two_factor_authentication_path end def show_delete @@ -109,7 +109,7 @@ def process_invalid_webauthn(form) render :new else flash[:error] = t('errors.webauthn_setup.general_error') - redirect_to account_url + redirect_to account_two_factor_authentication_path end end diff --git a/app/decorators/device_decorator.rb b/app/decorators/device_decorator.rb index fd9973a1b95..491a4cd39b8 100644 --- a/app/decorators/device_decorator.rb +++ b/app/decorators/device_decorator.rb @@ -1,10 +1,6 @@ DeviceDecorator = Struct.new(:device) do delegate :nice_name, :last_used_at, :id, to: :device - def device_partial - 'accounts/device_item' - end - def last_sign_in_location_and_ip I18n.t('account.index.sign_in_location_and_ip', location: last_location, ip: device.last_ip) end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index dda1b242f49..c778f111655 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -3,10 +3,6 @@ def title(title) content_for(:title) { title } end - def card_cls(cls) - content_for(:card_cls) { cls } - end - def background_cls(cls) content_for(:background_cls) { cls } end diff --git a/app/view_models/account_show.rb b/app/view_models/account_show.rb index f04d2f25403..dc060426bb9 100644 --- a/app/view_models/account_show.rb +++ b/app/view_models/account_show.rb @@ -9,24 +9,12 @@ def initialize(decrypted_pii:, personal_key:, decorated_user:, locked_for_sessio @pii = determine_pii end - def header_partial - 'accounts/header' + def show_personal_key_partial? + personal_key.present? end - def personal_key_partial - if personal_key.present? - 'accounts/personal_key' - else - 'shared/null' - end - end - - def password_reset_partial - if decorated_user.password_reset_profile.present? - 'accounts/password_reset' - else - 'shared/null' - end + def show_password_reset_partial? + decorated_user.password_reset_profile.present? end def pending_profile_partial @@ -41,10 +29,6 @@ def pending_profile_partial end end - def badges_partial - 'accounts/badges' - end - def unphishable_badge_partial return 'shared/null' unless MfaPolicy.new(decorated_user.user).unphishable? 'accounts/unphishable_badge' @@ -71,14 +55,6 @@ def show_pii_partial? decrypted_pii.present? || decorated_user.identity_verified? end - def pii_partial - if show_pii_partial? - 'accounts/pii' - else - 'shared/null' - end - end - def totp_partial if TwoFactorAuthentication::AuthAppPolicy.new(decorated_user.user).enabled? disable_totp_partial @@ -113,16 +89,13 @@ def enable_piv_cac_partial 'accounts/actions/enable_piv_cac' end - def manage_personal_key_partial - yield if decorated_user.password_reset_profile.blank? - end - - def personal_key_action_partial - 'accounts/actions/manage_personal_key' - end - - def personal_key_item_partial - 'accounts/personal_key_item_heading' + def show_manage_personal_key_partial? + if TwoFactorAuthentication::PersonalKeyPolicy.new(decorated_user.user).visible? && + decorated_user.password_reset_profile.blank? + true + else + false + end end def backup_codes_partial @@ -145,10 +118,6 @@ def backup_codes_generated_at decorated_user.user.backup_code_configurations.order(created_at: :asc).first&.created_at end - def recent_event_partial - 'accounts/event_item' - end - def header_personalization return decrypted_pii.first_name if decrypted_pii.present? diff --git a/app/view_models/navigation.rb b/app/view_models/navigation.rb new file mode 100644 index 00000000000..70605c16286 --- /dev/null +++ b/app/view_models/navigation.rb @@ -0,0 +1,44 @@ +class Navigation + include Rails.application.routes.url_helpers + + NavItem = Struct.new(:title, :href, :children) + + def initialize(user:) + @user = user + end + + def navigation_items + [ + NavItem.new(I18n.t('account.navigation.your_account'), account_path, [ + NavItem.new(I18n.t('account.navigation.add_email'), add_email_path), + NavItem.new(I18n.t('account.navigation.edit_password'), manage_password_path), + NavItem.new(I18n.t('account.navigation.delete_account'), account_delete_path), + ]), + NavItem.new(I18n.t('account.navigation.two_factor_authentication'), + account_two_factor_authentication_path, [ + NavItem.new(I18n.t('account.navigation.add_phone_number'), add_phone_path), + NavItem.new(I18n.t('account.navigation.add_authentication_apps'), + authenticator_setup_url), + NavItem.new(I18n.t('account.navigation.add_security_key'), webauthn_setup_path), + NavItem.new(I18n.t('account.navigation.add_federal_id'), setup_piv_cac_path), + NavItem.new(I18n.t('account.navigation.get_backup_codes'), + backup_codes_path), + ]), + NavItem.new(I18n.t('account.navigation.connected_accounts'), + account_connected_accounts_path, []), + NavItem.new(I18n.t('account.navigation.history'), account_history_path, [ + NavItem.new(I18n.t('account.navigation.forget_browsers'), + forget_all_browsers_path), + ]), + NavItem.new(I18n.t('account.navigation.customer_support'), MarketingSite.help_url, []), + ] + end + + def backup_codes_path + if TwoFactorAuthentication::BackupCodePolicy.new(@user).configured? + backup_code_regenerate_path + else + backup_code_create_path + end + end +end diff --git a/app/views/accounts/_account_item.html.erb b/app/views/accounts/_account_item.html.erb deleted file mode 100644 index 9a75c9380e3..00000000000 --- a/app/views/accounts/_account_item.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -
-
-
- <%= name %> -
-
- <%= content if local_assigns.key? :content %> -
-
-
- <% if local_assigns.key? :path %> - <%= render action, path: path, name: name %> - <% elsif local_assigns.key? :action %> - <%= render action %> - <% end %> -
-
diff --git a/app/views/accounts/_auth_apps.html.erb b/app/views/accounts/_auth_apps.html.erb index 24331524bc1..4ebfaea727d 100644 --- a/app/views/accounts/_auth_apps.html.erb +++ b/app/views/accounts/_auth_apps.html.erb @@ -1,10 +1,10 @@ -
-
-
- Authentication apps -
+
+
+

+ <%= t('headings.account.authentication_apps') %> +

<% if current_user.auth_app_configurations.count < Figaro.env.max_auth_apps_per_account.to_i %> -
+
@@ -12,19 +12,21 @@ <% end %>
- <% MfaContext.new(current_user).auth_app_configurations.each do |auth_app_configuration| %> -
-
- diff --git a/app/views/accounts/_backup_codes.html.erb b/app/views/accounts/_backup_codes.html.erb index fa01a4283b0..f76c914f580 100644 --- a/app/views/accounts/_backup_codes.html.erb +++ b/app/views/accounts/_backup_codes.html.erb @@ -1,22 +1,27 @@ -
-
-
<%= t 'forms.backup_code.title' %>
-
- <% if TwoFactorAuthentication::BackupCodePolicy.new(current_user).configured? %> -

- <%= t 'account.index.backup_codes_exist' %> -

-

- <%= - local_time(@view_model.backup_codes_generated_at, t('time.formats.event_timestamp')) - %> -

- <% else %> - <%= t 'account.index.backup_codes_no_exist' %> - <% end %> -
-
-
+
+

+ <%= t('forms.backup_code.title') %> +

+
<%= render @view_model.backup_codes_partial %>
+
+ <% if TwoFactorAuthentication::BackupCodePolicy.new(current_user).configured? %> +
+ <%= t 'account.index.backup_codes_exist' %> + <%= + local_time(@view_model.backup_codes_generated_at, t('time.formats.event_timestamp')) + %> +
+
+ <% if MfaPolicy.new(current_user).multiple_factors_enabled? %> + <%= link_to t('forms.buttons.delete'), backup_code_delete_path %> + <% end %> +
+ <% else %> +
+ <%= t 'account.index.backup_codes_no_exist' %> +
+ <% end %> +
diff --git a/app/views/accounts/_connected_app.html.erb b/app/views/accounts/_connected_app.html.erb index 4d51ad1f4ef..6d879992008 100644 --- a/app/views/accounts/_connected_app.html.erb +++ b/app/views/accounts/_connected_app.html.erb @@ -1,4 +1,4 @@ -
+
diff --git a/app/views/accounts/_delete_account_item_heading.html.erb b/app/views/accounts/_delete_account_item_heading.html.erb deleted file mode 100644 index 2500a36cfa0..00000000000 --- a/app/views/accounts/_delete_account_item_heading.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= t('account.items.delete_your_account') %> diff --git a/app/views/accounts/_device_item.html.erb b/app/views/accounts/_device_item.html.erb index b1fd7dbbe3c..c2e9bb38e4c 100644 --- a/app/views/accounts/_device_item.html.erb +++ b/app/views/accounts/_device_item.html.erb @@ -1,12 +1,12 @@ -
-
-
-
+
+
+
+
<%= device.nice_name %>
<%= device.last_sign_in_location_and_ip %>
-
+
<%= local_time(device.happened_at, t('time.formats.event_timestamp')) %>
<%= link_to t('headings.account.events'), account_events_path(id: device.id) %> diff --git a/app/views/accounts/_emails.html.erb b/app/views/accounts/_emails.html.erb index 54d637c0b35..d86112d15f1 100644 --- a/app/views/accounts/_emails.html.erb +++ b/app/views/accounts/_emails.html.erb @@ -1,20 +1,20 @@ -
-
-
+
+
+

<%= t('account.index.email_addresses') %> -

-
+ +
<% if EmailPolicy.new(current_user).can_add_email? %> -
<% @view_model.decorated_user.visible_email_addresses.each do |email| %> -