Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions app/javascript/packs/state-guidance.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { t } from '@18f/identity-i18n';

function jurisdictionExtrasHintText(jurisdiction) {
switch (jurisdiction) {
case 'TX':
return t('in_person_proofing.form.state_id.state_id_number_texas_hint');
default:
return t('in_person_proofing.form.state_id.state_id_number_hint');
}
}

export function showOrHideJurisdictionExtras(jurisdictionCode) {
document.querySelectorAll('.jurisdiction-extras').forEach((element) => {
element.textContent = jurisdictionExtrasHintText(jurisdictionCode);
const hasJurisdictionSpecificHint =
jurisdictionCode &&
document.querySelectorAll(`.jurisdiction-extras [data-state=${jurisdictionCode}]`).length > 0;

document.querySelectorAll<HTMLElement>(`.jurisdiction-extras [data-state]`).forEach((element) => {
const shouldShow =
element.dataset.state === jurisdictionCode ||
(!hasJurisdictionSpecificHint && element.dataset.state === 'default');
element.classList.toggle('display-none', !shouldShow);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need display-none? it seems shouldShow would always be true.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to show one but hide all the others, so this does that in one loop

});
}

Expand Down
29 changes: 28 additions & 1 deletion app/views/idv/in_person/state_id.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,37 @@
) %>
</div>
<div class="margin-bottom-5">
<% state_id_number_hint_default = capture do %>
<%= t('in_person_proofing.form.state_id.state_id_number_hint') %>
<% [
[t('in_person_proofing.form.state_id.state_id_number_hint_spaces'), ' '],
[t('in_person_proofing.form.state_id.state_id_number_hint_forward_slashes'), '/'],
[t('in_person_proofing.form.state_id.state_id_number_hint_asterisks'), '*'],
[t('in_person_proofing.form.state_id.state_id_number_hint_dashes'), '-', true],
].each do |text, symbol, last| %>
<span class="usa-sr-only"><%= text %><%= ',' if !last %></span>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comma was probably the trickiest bit! I think leaving the comma inside each string is error prone.

if we were joining "plain" text, I would consider having us use someting like Array#to_sentence or safe_join to handle the commas, but making sure the comma stays inside the HTML tags makes that tricky

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice solution :superb: (needs a emoji)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very easy to grok. I say leave it. Seems like Array#to_sentence would require you to pass in the wrapping HTML for the conjoining elements as a param? This is just much more explicit.

<span aria-hidden="true"><%= symbol %></span>
<% end %>
<% end %>

<% state_id_number_hint = capture do %>
<% [
[:default, state_id_number_hint_default],
['TX', t('in_person_proofing.form.state_id.state_id_number_texas_hint')],
].each do |state, hint| %>
<%= content_tag(
:span,
hint,
class: state == :default ? nil : 'display-none',
data: { state: },
) %>
<% end %>
<% end %>

<%= render ValidatedFieldComponent.new(
name: :state_id_number,
form: f,
hint: t('in_person_proofing.form.state_id.state_id_number_hint'),
hint: state_id_number_hint,
hint_html: { class: ['tablet:grid-col-10', 'jurisdiction-extras'] },
input_html: { value: pii[:state_id_number] },
label: t('in_person_proofing.form.state_id.state_id_number'),
Expand Down
6 changes: 5 additions & 1 deletion config/locales/in_person_proofing/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ en:
state_id_jurisdiction_hint: This is the state that issued your ID
state_id_jurisdiction_prompt: '- Select -'
state_id_number: ID number
state_id_number_hint: 'May include letters, numbers, and the following symbols: / *-'
state_id_number_hint: 'May include letters, numbers, and the following symbols:'
state_id_number_hint_asterisks: asterisks
state_id_number_hint_dashes: dashes
state_id_number_hint_forward_slashes: forward slashes
state_id_number_hint_spaces: spaces
state_id_number_texas_hint: This is the 8-digit number on your ID. Enter only
numbers in this field.
zipcode: ZIP Code
Expand Down
6 changes: 5 additions & 1 deletion config/locales/in_person_proofing/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ es:
state_id_jurisdiction_hint: Este es el estado que emitió su identificación
state_id_jurisdiction_prompt: '- Seleccione -'
state_id_number: Número de identidad
state_id_number_hint: 'Puede incluir letras, números y los siguientes símbolos: / *-'
state_id_number_hint: 'Puede incluir letras, números y los siguientes símbolos:'
state_id_number_hint_asterisks: 'asteriscos'
state_id_number_hint_dashes: guiones
state_id_number_hint_forward_slashes: 'barras diagonal'
state_id_number_hint_spaces: 'espacios'
state_id_number_texas_hint: Este es el número de 8 dígitos de su ID. Introduzca
sólo números en este campo.
zipcode: Código postal
Expand Down
7 changes: 5 additions & 2 deletions config/locales/in_person_proofing/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ fr:
state_id_jurisdiction_hint: Il s’agit de l’État qui a émis votre pièce d’identité
state_id_jurisdiction_prompt: '- Sélectionnez -'
state_id_number: Numéro d’identification
state_id_number_hint: 'Il peut s’agir de lettres, de chiffres et des symboles
suivants: / *-'
state_id_number_hint: 'Il peut s’agir de lettres, de chiffres et des symboles suivants:'
state_id_number_hint_asterisks: 'des astérisques'
state_id_number_hint_dashes: 'des tirets'
state_id_number_hint_forward_slashes: 'des barres obliques'
state_id_number_hint_spaces: 'des espaces'
state_id_number_texas_hint: Il s’agit du numéro à huit chiffres figurant sur
votre carte d’identité. Entrez uniquement des chiffres dans ce champ.
zipcode: Code postal
Expand Down
44 changes: 36 additions & 8 deletions spec/javascript/packs/state-guidance-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,61 @@ describe('state-guidance', () => {
<div>
<select class="jurisdiction-state-selector">Select Dropdown</select>
</div>
<div class="jurisdiction-extras"></div>
<div class="jurisdiction-extras">
<span data-state="default">Default help text</span>
<span data-state="CA" class="display-none">CA help text</span>
<span data-state="TX" class="display-none">TX help text</span>
</div>
</div>
`;
});

it('includes Texas specific hint text when Texas is selected', () => {
const jurisdictionCode = 'TX';
showOrHideJurisdictionExtras(jurisdictionCode);
const elementInnerHtml = document.querySelector('.jurisdiction-extras')?.textContent;

expect(elementInnerHtml).to.eq('in_person_proofing.form.state_id.state_id_number_texas_hint');
const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
const texasText = document.querySelectorAll('.jurisdiction-extras [data-state=TX]');
const nonTexasText = document.querySelectorAll(
'.jurisdiction-extras [data-state].display-none',
);

expect(texasText.length).to.eq(1);
expect(texasText[0].classList.contains('display-none')).to.eq(false);

expect(nonTexasText.length + texasText.length).to.eq(allHintTexts.length);
});

it('includes default hint text when no state is selected', () => {
const jurisdictionCode = ' ';
const jurisdictionCode = '';
showOrHideJurisdictionExtras(jurisdictionCode);
const elementInnerHtml = document.querySelector('.jurisdiction-extras')?.textContent;

expect(elementInnerHtml).to.eq('in_person_proofing.form.state_id.state_id_number_hint');
const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
const defaultText = document.querySelectorAll('.jurisdiction-extras [data-state=default]');
const nonDefaultText = document.querySelectorAll(
'.jurisdiction-extras [data-state].display-none',
);

expect(defaultText.length).to.eq(1);
expect(defaultText[0].classList.contains('display-none')).to.eq(false);

expect(nonDefaultText.length + defaultText.length).to.eq(allHintTexts.length);
});

it('includes default hint text when a state without a state specific hint is selected', () => {
const jurisdictionCode = 'NY';
showOrHideJurisdictionExtras(jurisdictionCode);
const elementInnerHtml = document.querySelector('.jurisdiction-extras')?.textContent;

expect(elementInnerHtml).to.eq('in_person_proofing.form.state_id.state_id_number_hint');
const allHintTexts = document.querySelectorAll('.jurisdiction-extras [data-state]');
const defaultText = document.querySelectorAll('.jurisdiction-extras [data-state=default]');
const nonDefaultText = document.querySelectorAll(
'.jurisdiction-extras [data-state].display-none',
);

expect(defaultText.length).to.eq(1);
expect(defaultText[0].classList.contains('display-none')).to.eq(false);

expect(nonDefaultText.length + defaultText.length).to.eq(allHintTexts.length);
});
});
});
37 changes: 37 additions & 0 deletions spec/views/idv/in_person/state_id.html.erb_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'rails_helper'

RSpec.describe 'idv/in_person/state_id.html.erb' do
let(:pii) { {} }
let(:form) { Idv::StateIdForm.new(pii) }
let(:parsed_dob) { Date.new(1970, 1, 1) }

before do
allow(view).to receive(:url_for).and_return('https://example.com/')
end

subject(:render_template) do
render template: 'idv/in_person/state_id',
locals: { updating_state_id: true, form: form, pii: pii, parsed_dob: parsed_dob }
end

it 'renders state ID hint text with correct screenreader tags', aggregate_failures: true do
render_template

doc = Nokogiri::HTML(rendered)

jurisdiction_extras = doc.at_css('.jurisdiction-extras')

all_hints = jurisdiction_extras.css('[data-state]')
shown = jurisdiction_extras.css('[data-state]:not(.display-none)')
hidden = jurisdiction_extras.css('[data-state].display-none')

expect(shown.size).to eq(1), 'only shows one hint'
expect(shown.size + hidden.size).to eq(all_hints.size)

default_hint = jurisdiction_extras.at_css('[data-state=default]')
default_hint_screenreader_tags = default_hint.css('.usa-sr-only')
*first, last = default_hint_screenreader_tags.map(&:text)
expect(first).to all end_with(',')
expect(last).to_not end_with(',')
Comment on lines +34 to +35
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specs to make sure we get the commas correct inside the reader hint texts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

end
end