From 592623ad6aa9ea4ffc2992fdc98171fbc3067704 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 27 Sep 2022 10:21:21 -0400 Subject: [PATCH 01/13] Use legacy personal key implementation for account dashboard (#6996) **Why**: - Since the React implementation is being discontinued and slated for removal (LG-7386) - To avoid feature drift - To ensure consistency of personal key confirmation feature flag (#6821 / LG-7162) Effectively reverts #6453 [skip changelog] --- .../idv/personal_key_controller.rb | 2 -- app/javascript/packages/verify-flow/index.ts | 3 -- app/javascript/packs/verify-personal-key.tsx | 24 --------------- app/views/shared/_personal_key.html.erb | 2 +- app/views/users/personal_keys/show.html.erb | 6 +--- .../shared/_personal_key.html.erb_spec.rb | 29 +++++++++++++++++-- 6 files changed, 29 insertions(+), 37 deletions(-) delete mode 100644 app/javascript/packs/verify-personal-key.tsx diff --git a/app/controllers/idv/personal_key_controller.rb b/app/controllers/idv/personal_key_controller.rb index 20204bc3218..5e2ca39ee67 100644 --- a/app/controllers/idv/personal_key_controller.rb +++ b/app/controllers/idv/personal_key_controller.rb @@ -14,8 +14,6 @@ def show add_proofing_component finish_idv_session - - @confirm = FeatureManagement.idv_personal_key_confirmation_enabled? ? 'modal' : 'skip' end def update diff --git a/app/javascript/packages/verify-flow/index.ts b/app/javascript/packages/verify-flow/index.ts index dc68b5016c1..38708f4881f 100644 --- a/app/javascript/packages/verify-flow/index.ts +++ b/app/javascript/packages/verify-flow/index.ts @@ -6,9 +6,6 @@ export { default as Cancel } from './cancel'; export { default as VerifyFlow } from './verify-flow'; export { default as VerifyFlowStepIndicator, VerifyFlowPath } from './verify-flow-step-indicator'; -export { default as personalKeyStep } from './steps/personal-key'; -export { default as personalKeyConfirmStep } from './steps/personal-key-confirm'; - export type { FlowContextValue } from './context/flow-context'; export type { SecretValues } from './context/secrets-context'; export type { AddressVerificationMethod } from './context/address-verification-method-context'; diff --git a/app/javascript/packs/verify-personal-key.tsx b/app/javascript/packs/verify-personal-key.tsx deleted file mode 100644 index ede5e5c5af9..00000000000 --- a/app/javascript/packs/verify-personal-key.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { render } from 'react-dom'; -import { FormSteps } from '@18f/identity-form-steps'; -import { personalKeyStep, personalKeyConfirmStep } from '@18f/identity-verify-flow'; - -interface AppRootValues { - personalKey: string; -} - -interface AppRootElement extends HTMLElement { - dataset: DOMStringMap & AppRootValues; -} - -const appRoot = document.getElementById('app-root') as AppRootElement; -const appForm = document.getElementById('app-form') as HTMLFormElement; - -render( - appForm.submit()} - />, - appRoot, -); diff --git a/app/views/shared/_personal_key.html.erb b/app/views/shared/_personal_key.html.erb index 42dcdb62ea0..24e0c08288b 100644 --- a/app/views/shared/_personal_key.html.erb +++ b/app/views/shared/_personal_key.html.erb @@ -45,7 +45,7 @@ t('forms.buttons.continue'), update_path, class: 'display-block usa-button usa-button--big usa-button--wide personal-key-continue margin-top-5', - 'data-toggle': @confirm, + 'data-toggle': FeatureManagement.idv_personal_key_confirmation_enabled? ? 'modal' : 'skip', ) %> <%= render 'shared/personal_key_confirmation_modal', code: code, update_path: update_path %> <%== javascript_packs_tag_once 'personal-key-page-controller' %> diff --git a/app/views/users/personal_keys/show.html.erb b/app/views/users/personal_keys/show.html.erb index cdd1b7db1d8..f443fd7b135 100644 --- a/app/views/users/personal_keys/show.html.erb +++ b/app/views/users/personal_keys/show.html.erb @@ -1,7 +1,3 @@ <% title t('titles.personal_key') %> -<%= form_tag(manage_personal_key_path, method: 'post', id: 'app-form') %> -<%= content_tag(:div, '', id: 'app-root', data: { personal_key: @code }) do %> - <%= render 'shared/personal_key', code: @code, update_path: manage_personal_key_path %> -<% end %> -<%= javascript_packs_tag_once('verify-personal-key') %> +<%= render('shared/personal_key', code: @code, update_path: manage_personal_key_path) %> diff --git a/spec/views/shared/_personal_key.html.erb_spec.rb b/spec/views/shared/_personal_key.html.erb_spec.rb index bff0e986e8e..594c9060d64 100644 --- a/spec/views/shared/_personal_key.html.erb_spec.rb +++ b/spec/views/shared/_personal_key.html.erb_spec.rb @@ -4,6 +4,8 @@ RSpec.describe 'shared/_personal_key.html.erb' do let(:personal_key) { RandomPhrase.new(num_words: 4).to_s } + subject(:rendered) { render 'shared/personal_key', code: personal_key, update_path: '/test' } + describe 'download link' do around do |ex| # data_uri depends on URI.decode which was removed in Ruby 3.0 :sob: @@ -19,8 +21,6 @@ def self.decode(value) end it 'has the download attribute and a data: url for the personal key' do - render 'shared/personal_key', code: personal_key, update_path: '/test' - doc = Nokogiri::HTML(rendered) download_link = doc.at_css('a[download]') data_uri = URI::Data.new(download_link[:href]) @@ -29,4 +29,29 @@ def self.decode(value) expect(data_uri.data).to eq(personal_key) end end + + describe 'continue button' do + let(:idv_personal_key_confirmation_enabled) { nil } + + before do + allow(FeatureManagement).to receive(:idv_personal_key_confirmation_enabled?). + and_return(idv_personal_key_confirmation_enabled) + end + + context 'without idv personal key confirmation' do + let(:idv_personal_key_confirmation_enabled) { false } + + it 'renders button with [data-toggle="skip"]' do + expect(rendered).to have_css('[data-toggle="skip"]') + end + end + + context 'with idv personal key confirmation' do + let(:idv_personal_key_confirmation_enabled) { true } + + it 'renders button with [data-toggle="modal"]' do + expect(rendered).to have_css('[data-toggle="modal"]') + end + end + end end From 1f09e1b69adc1a340413004cf95acd2bc5c204a0 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Tue, 27 Sep 2022 12:37:00 -0400 Subject: [PATCH 02/13] Fix logging for password visibility toggle (#7030) * Fix logging for password visibility toggle **Why**: Frontend event logging map is case sensitive, so the event was not being matched as expected. * Use same path as "visit" command changelog: Internal, Analytics, Add logging for password visibility toggle clicked * Add extra logging * Try fetch wrapper for awaiting analytics logging completion * Run teardown in ensure handler Co-authored-by: Zach Margolis Co-authored-by: Zach Margolis --- app/controllers/frontend_log_controller.rb | 2 +- app/services/analytics_events.rb | 5 +++-- spec/features/users/sign_in_spec.rb | 13 +++++++++++- .../features/javascript_driver_helper.rb | 21 +++++++++++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/controllers/frontend_log_controller.rb b/app/controllers/frontend_log_controller.rb index 5516a0b690e..9e1fc4ec064 100644 --- a/app/controllers/frontend_log_controller.rb +++ b/app/controllers/frontend_log_controller.rb @@ -26,7 +26,7 @@ class FrontendLogController < ApplicationController 'IdV: download personal key' => :idv_personal_key_downloaded, 'IdV: Native camera forced after failed attempts' => :idv_native_camera_forced, 'Multi-Factor Authentication: download backup code' => :multi_factor_auth_backup_code_download, - 'Show Password Button Clicked' => :show_password_button_clicked, + 'Show Password button clicked' => :show_password_button_clicked, }.transform_values do |method| method.is_a?(Proc) ? method : AnalyticsEvents.instance_method(method) end.freeze diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 62627c65b99..d8aec192660 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -2672,8 +2672,9 @@ def contact_redirect(redirect_url:, step: nil, location: nil, flow: nil, **extra end # Tracks if a user clicks the "Show Password button" - def show_password_button_clicked - track_event('Show Password Button Clicked') + # @param [String] path URL path where the click occurred + def show_password_button_clicked(path:, **extra) + track_event('Show Password Button Clicked', path: path, **extra) end end # rubocop:enable Metrics/ModuleLength diff --git a/spec/features/users/sign_in_spec.rb b/spec/features/users/sign_in_spec.rb index 1ad82115b2d..fe0424f8c84 100644 --- a/spec/features/users/sign_in_spec.rb +++ b/spec/features/users/sign_in_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' feature 'Sign in' do + include JavascriptDriverHelper + before(:all) do @original_capyabara_wait = Capybara.default_max_wait_time Capybara.default_max_wait_time = 5 @@ -216,11 +218,20 @@ end scenario 'user can see and use password visibility toggle', js: true do + fake_analytics = FakeAnalytics.new + allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics) + visit new_user_session_path - check t('components.password_toggle.toggle_label') + with_awaited_fetch do + check t('components.password_toggle.toggle_label') + end expect(page).to have_css('input.password[type="text"]') + expect(fake_analytics).to have_logged_event( + 'Show Password Button Clicked', + path: new_user_session_path, + ) end scenario 'user session expires in amount of time specified by Devise config' do diff --git a/spec/support/features/javascript_driver_helper.rb b/spec/support/features/javascript_driver_helper.rb index 151067296e3..e568f3669c1 100644 --- a/spec/support/features/javascript_driver_helper.rb +++ b/spec/support/features/javascript_driver_helper.rb @@ -2,4 +2,25 @@ module JavascriptDriverHelper def javascript_enabled? %i[headless_chrome headless_chrome_mobile].include?(Capybara.current_driver) end + + def with_awaited_fetch + setup_js = <<~JS + window._fetch = window.fetch; + window.fetch = async (...args) => { + window.isFetching = true; + const result = await window._fetch.call(window, ...args); + window.isFetching = false; + return result; + }; + JS + teardown_js = 'window.fetch = window._fetch; delete window._fetch;' + + page.execute_script(setup_js) + yield + Timeout.timeout(Capybara.default_max_wait_time) do + loop if page.evaluate_script('window.isFetching') + end + ensure + page.execute_script(teardown_js) + end end From 3e7feb4543d583a911d896f1991f250c0db10054 Mon Sep 17 00:00:00 2001 From: Mitchell Henke Date: Tue, 27 Sep 2022 12:00:15 -0500 Subject: [PATCH 03/13] Make sign-in page buttons big to improve button style consistency (#7032) * Make sign-in page buttons big to improve consistency changelog: Improvements, Style, Make sign-in page buttons big to improve consistency * Update app/views/devise/sessions/new.html.erb Co-authored-by: Andrew Duthie * Update app/views/devise/sessions/new.html.erb Co-authored-by: Andrew Duthie Co-authored-by: Andrew Duthie --- app/views/devise/sessions/new.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index ad1d516397c..113ae6dc60e 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -34,14 +34,14 @@ ) %> <%= f.input :request_id, as: :hidden, input_html: { value: @request_id } %>
- <%= f.submit t('links.next'), full_width: true, big: false, wide: false %> + <%= f.submit t('links.next'), full_width: true, wide: false %>

<%= t('headings.create_account_with_sp.cta', app_name: APP_NAME) %>

<%= link_to( t('links.create_account'), sign_up_email_url(request_id: @request_id), - class: 'text-no-underline usa-button usa-button--outline usa-button--full-width margin-top-1', + class: 'usa-button usa-button--big usa-button--outline usa-button--full-width margin-top-1', ) %>
<% end %> From 8c3688d6f027472b53ae7c9876c58eca68d9d604 Mon Sep 17 00:00:00 2001 From: Eric Gade <105373963+eric-gade@users.noreply.github.com> Date: Tue, 27 Sep 2022 14:21:34 -0400 Subject: [PATCH 04/13] LG-7242 Accessible Icons (#6983) * Updating all warning icon images to new icon * Updating error icon * Adding personal-key icon Will need to update where it gets used, since this appears to be the first instance of the icon * Updating info-question icon * Replacing error-lock icon * Updating icon names and styling in templates/stylesheets -- What We have replaced half a dozen existing icons with new SVGs. These have different names in some cases, so the references need to be replaced in templates. Additionally, these icons require larger display sizes given their circular shape, so we need to find corresponding template tags and make sure they are given the correct dimensions (88x88px) changelog: Internal, Assets, updating icon images and references * Updating icon image dimensions in templates changelog: Internal, Assets, updating icon images and references * Updating remaining templates with new icons sizes changelog: Internal, Accessibility, updating icons * Updating SVG assets to not have inline styles changelog: Internal, Accessibility, updating accessible icons * Removing now unused image from assets changelog: Internal, Accessibility, updating to more accessible icons * Updating alt test for confirm delete account icon changelog: Internal, Accessibility, updating to more accessible icons * Fixing lints changelog: Internal, Accessibility, switching to more accessible icons * Adding localized alt text for new icons Also updating any corresponding templates to use the new localizations. changelog: Internal, Accessibility, updating to more accessible icons * Fixing es local yaml typo * Updating templates and modals to use new icon css changelog: Internal, Accessibility, adding more accessible icons * Updating status page component with new icon locales changelog: Internal, Accessibility, adding more accessible icons * Removing old icon css from _modal changelog: Internal, Accessibility, adding more accessible icons * Fixing dont have personal key modal styling changelog: Internal, Accessibility, adding more accessible icons * Update app/assets/stylesheets/components/_icon.scss Co-authored-by: Andrew Duthie * Switching location of icon locales Was previously in `titles`, but moved to the more appropriate locales directory of `image_description` changelog: Internal, Accessibility, updating to more accessible icons * Changing lg-icon to alert-icon changelog: Internal, Accessibility, adding more accessible icons * Switching alert_icon to its own sass partial changelog: Internal, Accessibility, adding more accessible icons * Creating a new ViewComponent for alert icons changelog: Internal, Accessibility, adding more accessible icons * Creating new AlertIcon ViewComponent with tests Also updating the various templates to use the new ViewComponent changelog: Internal, Accessibility, adding more accessible icons * Ensuring frontend alert icons use the correct width/height changelog: Internal, Accessibility, adding more accessible icons * Fixing broken JS test i18n assumption changelog: Internal, Accessibility, adding more accessible icons * Updating sass partial for inclusion changelog: Internal, Accessibility, adding more accessible icons * Updating StatusPageComponent to use AlertIconComponent This eliminated insonsistencies between the way these two label and display the icon images that they share. changelog: Internal, Accessibility, adding more accessible icons * Removing unused locales changelog: Internal, Accessibility, adding more accessible icons * Update app/views/sign_up/registrations/_required_pii_accordion.html.erb Co-authored-by: Andrew Duthie * Ensuring that we raise an error if invalid icon_name is passed Also updating the signature of the initialization method changelog: Internal, Accessibility, adding more accessible icons * Updating views to use new AlertIconComponent initializer changelog: Internal, Accessibility, adding more accessible icons * Simplifying custom tag options for alt text changelog: Internal, Accessibility, adding more accessible icons * Ensure we are using symbols for icon names changelog: Internal, Accessibility, adding more accessible icons * Fixing initializer of AlertIconComponent changelog: Internal, Accessibility, adding more accessible icons * Moving personal key icon image to status Also updating and corresponding location references. changelog: Internal, Accessibility, adding more accessible icons * Removing redundant alert-icon class declaration changelog: Internal, Accessibility, adding more accessible icons * Restoring get-started accordion personal key image Also reverting to plain image_tag for the rendering, as with other sibling icon images in the partial changelog: Internal, Accessibility, adding more accessible icons * Accounting for possible size tag option in component template changelog: Internal, Accessibility, adding more accessible icons * Update app/components/alert_icon_component.rb Co-authored-by: Andrew Duthie * Fixing conflicting linter errors changelog: Internal, Accessibility, adding more accessible icons * Refactoring width, height, and size interplay We are also adding a couple of tests to ensure that AlertIconComponent is correctly handling the logic if width, height, and size attributes changelog: Internal, Accessibility, adding more accessible icons * Empty commit for gitlab CI changelog: Internal, Accessibility, adding more accessible icons * Cleaning up tests changelog: Internal, Accessibility, adding more accessible icons * Removing casing for size option It's not currently being used, so we are removing any handling of this option changelog: Internal, Accessibility, adding more accessible icons Co-authored-by: Andrew Duthie --- app/assets/images/alert/warning.svg | 2 +- .../personal-key.svg} | 0 app/assets/images/personal-key/warning.svg | 2 +- app/assets/images/status/delete.svg | 1 + app/assets/images/status/error-lock.svg | 2 +- app/assets/images/status/error.svg | 2 +- app/assets/images/status/info-question.svg | 2 +- app/assets/images/status/personal-key.svg | 1 + app/assets/images/status/warning.svg | 2 +- .../stylesheets/components/_alert-icon.scss | 24 ++++++++++ app/assets/stylesheets/components/_modal.scss | 11 ----- .../stylesheets/components/_personal-key.scss | 11 ----- app/assets/stylesheets/components/all.scss | 1 + app/components/alert_icon_component.html.erb | 1 + app/components/alert_icon_component.rb | 45 +++++++++++++++++++ app/components/status_page_component.html.erb | 3 +- app/components/status_page_component.rb | 22 +++++---- .../packages/components/status-page.spec.tsx | 4 +- .../packages/components/status-page.tsx | 16 ++++--- .../personal-key-confirm-step.tsx | 4 +- .../confirm_delete_account/show.html.erb | 8 ++-- app/views/banned_user/show.html.erb | 2 +- app/views/idv/shared/_error.html.erb | 14 +++--- app/views/reactivate_account/_modal.html.erb | 8 +++- .../_personal_key_confirmation_modal.html.erb | 2 +- .../_required_pii_accordion.html.erb | 2 +- .../sms_opt_in/error.html.erb | 5 +-- .../sms_opt_in/new.html.erb | 5 +-- .../backup_code_setup/confirm_delete.html.erb | 2 +- .../users/backup_code_setup/edit.html.erb | 2 +- .../piv_cac_setup/confirm_delete.html.erb | 2 +- .../service_provider_inactive/index.html.erb | 2 +- .../users/totp_setup/confirm_delete.html.erb | 2 +- .../users/verify_personal_key/new.html.erb | 2 +- .../users/webauthn_setup/delete.html.erb | 6 +-- config/locales/components/en.yml | 6 --- config/locales/components/es.yml | 6 --- config/locales/components/fr.yml | 6 --- config/locales/errors/en.yml | 3 -- config/locales/errors/es.yml | 3 -- config/locales/errors/fr.yml | 3 -- config/locales/idv/en.yml | 1 - config/locales/idv/es.yml | 1 - config/locales/idv/fr.yml | 1 - config/locales/image_description/en.yml | 6 +++ config/locales/image_description/es.yml | 6 +++ config/locales/image_description/fr.yml | 6 +++ spec/components/alert_icon_component_spec.rb | 35 +++++++++++++++ spec/components/status_page_component_spec.rb | 4 +- spec/i18n_spec.rb | 5 --- spec/views/idv/shared/_error.html.erb_spec.rb | 4 +- 51 files changed, 191 insertions(+), 125 deletions(-) rename app/assets/images/{p-key.svg => get-started/personal-key.svg} (100%) create mode 100644 app/assets/images/status/delete.svg create mode 100644 app/assets/images/status/personal-key.svg create mode 100644 app/assets/stylesheets/components/_alert-icon.scss create mode 100644 app/components/alert_icon_component.html.erb create mode 100644 app/components/alert_icon_component.rb create mode 100644 spec/components/alert_icon_component_spec.rb diff --git a/app/assets/images/alert/warning.svg b/app/assets/images/alert/warning.svg index 733fb4dd56a..a7da87824e8 100644 --- a/app/assets/images/alert/warning.svg +++ b/app/assets/images/alert/warning.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/p-key.svg b/app/assets/images/get-started/personal-key.svg similarity index 100% rename from app/assets/images/p-key.svg rename to app/assets/images/get-started/personal-key.svg diff --git a/app/assets/images/personal-key/warning.svg b/app/assets/images/personal-key/warning.svg index cefee48e1ae..a7da87824e8 100644 --- a/app/assets/images/personal-key/warning.svg +++ b/app/assets/images/personal-key/warning.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/status/delete.svg b/app/assets/images/status/delete.svg new file mode 100644 index 00000000000..fccaf89948d --- /dev/null +++ b/app/assets/images/status/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/status/error-lock.svg b/app/assets/images/status/error-lock.svg index 6dfe19acde3..54105f34a18 100644 --- a/app/assets/images/status/error-lock.svg +++ b/app/assets/images/status/error-lock.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/status/error.svg b/app/assets/images/status/error.svg index 95d8c6871a9..43d1cb11650 100644 --- a/app/assets/images/status/error.svg +++ b/app/assets/images/status/error.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/status/info-question.svg b/app/assets/images/status/info-question.svg index 6c42e483512..9662ada24ac 100644 --- a/app/assets/images/status/info-question.svg +++ b/app/assets/images/status/info-question.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/status/personal-key.svg b/app/assets/images/status/personal-key.svg new file mode 100644 index 00000000000..b503cdb03ec --- /dev/null +++ b/app/assets/images/status/personal-key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/status/warning.svg b/app/assets/images/status/warning.svg index 5ad6ca821f9..a7da87824e8 100644 --- a/app/assets/images/status/warning.svg +++ b/app/assets/images/status/warning.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/stylesheets/components/_alert-icon.scss b/app/assets/stylesheets/components/_alert-icon.scss new file mode 100644 index 00000000000..bcf0023df12 --- /dev/null +++ b/app/assets/stylesheets/components/_alert-icon.scss @@ -0,0 +1,24 @@ +// Login Specific Icons (non-uswds) +.alert-icon { + width: 88px; + height: 88px; +} + +// For displaying icons as "badges" +// at the top of modals +.iconic-modal-badge { + &::before { + background-repeat: no-repeat; + background-size: contain; + content: ''; + position: absolute; + left: 50%; + top: 0px; + transform: translateX(-50%) translateY(-50%); + height: 88px; + width: 88px; + } + &.personal-key-badge::before { + background-image: url('status/personal-key.svg'); + } +} diff --git a/app/assets/stylesheets/components/_modal.scss b/app/assets/stylesheets/components/_modal.scss index 98cefce9c5c..c23c73a07c3 100644 --- a/app/assets/stylesheets/components/_modal.scss +++ b/app/assets/stylesheets/components/_modal.scss @@ -34,17 +34,6 @@ margin-right: auto; position: relative; - &.key-badge::before { - background-image: url('p-key.svg'); - background-repeat: no-repeat; - content: ''; - height: 60px; - left: 45%; - position: absolute; - top: -25px; - width: 60px; - } - &[class^='modal-']::before, &[class*=' modal-']::before { background-repeat: no-repeat; diff --git a/app/assets/stylesheets/components/_personal-key.scss b/app/assets/stylesheets/components/_personal-key.scss index 91dc4ae937a..e359ee51661 100644 --- a/app/assets/stylesheets/components/_personal-key.scss +++ b/app/assets/stylesheets/components/_personal-key.scss @@ -1,16 +1,5 @@ .key-badge { position: relative; - - &::before { - background-image: url('p-key.svg'); - background-repeat: no-repeat; - content: ''; - height: 60px; - left: 45%; - position: absolute; - top: -25px; - width: 60px; - } } .separator-text__code { diff --git a/app/assets/stylesheets/components/all.scss b/app/assets/stylesheets/components/all.scss index 94378454922..53caced834b 100644 --- a/app/assets/stylesheets/components/all.scss +++ b/app/assets/stylesheets/components/all.scss @@ -1,4 +1,5 @@ @import 'account-header'; +@import 'alert-icon'; @import 'banner'; @import 'block-link'; @import 'btn'; diff --git a/app/components/alert_icon_component.html.erb b/app/components/alert_icon_component.html.erb new file mode 100644 index 00000000000..6293bfd687e --- /dev/null +++ b/app/components/alert_icon_component.html.erb @@ -0,0 +1 @@ +<%= image_tag(source, alt: alt_text, **size_attributes, **tag_options, class: css_class) %> diff --git a/app/components/alert_icon_component.rb b/app/components/alert_icon_component.rb new file mode 100644 index 00000000000..cf0e0b76127 --- /dev/null +++ b/app/components/alert_icon_component.rb @@ -0,0 +1,45 @@ +class AlertIconComponent < BaseComponent + ICON_SOURCE = { + warning: 'status/warning.svg', + error: 'status/error.svg', + error_lock: 'status/error-lock.svg', + personal_key: 'status/personal-key.svg', + info_question: 'status/info-question.svg', + delete: 'status/delete.svg', + } + DEFAULT_WIDTH = 88 + DEFAULT_HEIGHT = 88 + + attr_reader :tag_options, :icon_name + + def initialize(icon_name: :warning, **tag_options) + if !ICON_SOURCE.key?(icon_name) + raise ArgumentError, + "`icon_name` #{icon_name} is invalid, expected one of #{ICON_SOURCE.keys}" + end + @icon_name = icon_name + @tag_options = tag_options + end + + def render? + ICON_SOURCE.key?(icon_name) + end + + def source + asset_url(ICON_SOURCE[icon_name]) + end + + def alt_text + t("image_description.#{icon_name}") + end + + def css_class + classes = [*tag_options[:class]] + classes << 'alert-icon' + classes + end + + def size_attributes + { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT } + end +end diff --git a/app/components/status_page_component.html.erb b/app/components/status_page_component.html.erb index 3d4ec71e3d7..e6cb2865e3b 100644 --- a/app/components/status_page_component.html.erb +++ b/app/components/status_page_component.html.erb @@ -1,5 +1,4 @@ -<%= image_tag(icon_src, width: 54, height: 54, alt: icon_alt, class: 'display-block margin-bottom-4') %> - +<%= render AlertIconComponent.new(icon_name: icon_name, class: 'display-block margin-bottom-4', width: 54, height: 54) %> <%= header %> <%= content %> diff --git a/app/components/status_page_component.rb b/app/components/status_page_component.rb index cb9ca3e1991..66e55392edd 100644 --- a/app/components/status_page_component.rb +++ b/app/components/status_page_component.rb @@ -5,6 +5,8 @@ class StatusPageComponent < BaseComponent error: [nil, :lock], }.freeze + VALID_STATUS = %i[info error warning].freeze + renders_one :header, ::PageHeadingComponent renders_many :action_buttons, ->(**button_options) do ButtonComponent.new(**button_options, big: true, wide: true) @@ -14,8 +16,8 @@ class StatusPageComponent < BaseComponent attr_reader :status, :icon def initialize(status: :error, icon: nil) - if !ICONS.key?(status) - raise ArgumentError, "`status` #{status} is invalid, expected one of #{ICONS.keys}" + if !VALID_STATUS.include?(status) + raise ArgumentError, "`status` #{status} is invalid, expected one of #{VALID_STATUS}" end if !ICONS[status].include?(icon) @@ -26,15 +28,11 @@ def initialize(status: :error, icon: nil) @status = status end - def icon_src - image_path("status/#{[status, icon].compact.join('-')}", extname: '.svg') - end - - def icon_alt - # i18n-tasks-use t('components.status_page.icons.error') - # i18n-tasks-use t('components.status_page.icons.question') - # i18n-tasks-use t('components.status_page.icons.warning') - # i18n-tasks-use t('components.status_page.icons.lock') - t(icon || status, scope: [:components, :status_page, :icons]) + def icon_name + if @icon + "#{status}_#{icon}".to_sym + else + status.to_sym + end end end diff --git a/app/javascript/packages/components/status-page.spec.tsx b/app/javascript/packages/components/status-page.spec.tsx index dcecc93327e..d9abfb5854f 100644 --- a/app/javascript/packages/components/status-page.spec.tsx +++ b/app/javascript/packages/components/status-page.spec.tsx @@ -16,7 +16,7 @@ describe('StatusPage', () => { const content = getByText('Content'); expect(icon.getAttribute('src')).to.equal('status/error.svg'); - expect(icon.getAttribute('alt')).to.equal('components.status_page.icons.error'); + expect(icon.getAttribute('alt')).to.equal('image_description.error'); expect(content).to.exist(); expect(heading.textContent).to.equal('Header'); expect(icon.compareDocumentPosition(heading)).to.equal(Node.DOCUMENT_POSITION_FOLLOWING); @@ -30,7 +30,7 @@ describe('StatusPage', () => { const icon = getByRole('img'); expect(icon.getAttribute('src')).to.equal('status/info-question.svg'); - expect(icon.getAttribute('alt')).to.equal('components.status_page.icons.question'); + expect(icon.getAttribute('alt')).to.equal('image_description.info_question'); }); }); diff --git a/app/javascript/packages/components/status-page.tsx b/app/javascript/packages/components/status-page.tsx index 1559ea9fb9f..f9d5f2268ed 100644 --- a/app/javascript/packages/components/status-page.tsx +++ b/app/javascript/packages/components/status-page.tsx @@ -35,10 +35,10 @@ const STATUS_ICONS: Record> = { * Text to be used as text alternative for icon. */ const STATUS_ALT: Record = { - error: t('components.status_page.icons.error'), - question: t('components.status_page.icons.question'), - warning: t('components.status_page.icons.warning'), - lock: t('components.status_page.icons.lock'), + error: t('image_description.error'), + question: t('image_description.info_question'), + warning: t('image_description.warning'), + lock: t('image_description.error_lock'), }; interface StatusPageProps { @@ -86,7 +86,13 @@ function StatusPage({ return ( <> - {alt} + {alt} {header} {children} {actionButtons.length > 0 && ( diff --git a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-confirm-step.tsx b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-confirm-step.tsx index 1629595dcd6..73279618e28 100644 --- a/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-confirm-step.tsx +++ b/app/javascript/packages/verify-flow/steps/personal-key-confirm/personal-key-confirm-step.tsx @@ -27,10 +27,10 @@ function PersonalKeyConfirmStep(stepProps: PersonalKeyConfirmStepProps) {
{t('idv.titles.personal_key')}
{t('forms.personal_key.title')} diff --git a/app/views/account_reset/confirm_delete_account/show.html.erb b/app/views/account_reset/confirm_delete_account/show.html.erb index bfb1bbcad82..4c70af1a123 100644 --- a/app/views/account_reset/confirm_delete_account/show.html.erb +++ b/app/views/account_reset/confirm_delete_account/show.html.erb @@ -1,10 +1,8 @@ <% title t('account_reset.confirm_delete_account.title') %>
- <%= image_tag( - asset_url('status/error.svg'), - size: '48x48', - alt: t('errors.alt.error'), - class: 'pin-top pin-x margin-top-neg-3 margin-x-auto', + <%= render AlertIconComponent.new( + icon_name: :delete, + class: 'pin-top pin-x margin-top-neg-5 margin-x-auto', ) %> <%= render PageHeadingComponent.new.with_content(t('account_reset.confirm_delete_account.title')) %>

<%= t('account_reset.confirm_delete_account.info_html', email: email) %>

diff --git a/app/views/banned_user/show.html.erb b/app/views/banned_user/show.html.erb index 25d196ff33f..7adee360f68 100644 --- a/app/views/banned_user/show.html.erb +++ b/app/views/banned_user/show.html.erb @@ -1,6 +1,6 @@ <% title t('banned_user.title') %> -<%= image_tag('status/error.svg', width: 54, alt: t('errors.alt.error'), class: 'display-block margin-bottom-4') %> +<%= render AlertIconComponent.new(icon_name: :error, class: 'display-block margin-bottom-4') %> <%= render PageHeadingComponent.new.with_content(t('banned_user.title')) %>

<%= t('banned_user.details') %> diff --git a/app/views/idv/shared/_error.html.erb b/app/views/idv/shared/_error.html.erb index a9eb2a09f97..b6b0cd71640 100644 --- a/app/views/idv/shared/_error.html.erb +++ b/app/views/idv/shared/_error.html.erb @@ -9,16 +9,14 @@ locals: * options: Array of troubleshooting options. %> <% if local_assigns.fetch(:type, :error) == :error - image_src = 'status/error.svg' + icon_name = :error troubleshooting_heading = t('idv.troubleshooting.headings.need_assistance') - alt = t('errors.alt.error') - else - image_src = 'status/warning.svg' - troubleshooting_heading = t('components.troubleshooting_options.default_heading') - alt = t('errors.alt.warning') - end %> +else + icon_name = :warning + troubleshooting_heading = t('components.troubleshooting_options.default_heading') +end %> <% title local_assigns.fetch(:title, heading) %> -<%= image_tag(image_src, width: 54, alt: alt, class: 'display-block margin-bottom-4') %> +<%= render AlertIconComponent.new(icon_name: icon_name, class: 'display-block margin-bottom-4') %> <%= render PageHeadingComponent.new.with_content(heading) %> diff --git a/app/views/reactivate_account/_modal.html.erb b/app/views/reactivate_account/_modal.html.erb index dbb10f6849a..14446b6b2a7 100644 --- a/app/views/reactivate_account/_modal.html.erb +++ b/app/views/reactivate_account/_modal.html.erb @@ -1,6 +1,9 @@