-
Notifications
You must be signed in to change notification settings - Fork 167
LG-6343: Implement email template for "Ready to verify" #6585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9112edb
84694a0
d96c0bb
f4fc75e
b1e676e
edb81b2
ee976c3
fbffdd6
44a4518
9682e9e
5235e05
b748e3b
f4650ba
854aced
63f44c0
7830f02
6684730
8bb5a45
4dbc911
52b2795
a781e96
946d268
269cd09
240183c
cdc01c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,7 +105,7 @@ install: | |
|
|
||
| specs: | ||
| stage: test | ||
| parallel: 7 | ||
| parallel: 11 | ||
| cache: | ||
| - <<: *ruby_cache | ||
| - <<: *yarn_cache | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Email Images | ||
|
|
||
| This folder contains images for exclusive use by mailer templates. This includes email-specific imagery, and also variants of existing assets. For example, since [SVG images are not well-supported](https://www.caniemail.com/features/image-svg/) in all email clients, this folder may include rasterized versions of common SVG images. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| .barcode.barby-barcode { | ||
| width: auto; | ||
| table-layout: fixed; | ||
| border-spacing: 0; | ||
| } | ||
|
|
||
| .barcode .barby-cell { | ||
| width: 2px; | ||
| height: 96px; | ||
|
|
||
| &.on { | ||
| background-color: #000; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| <%# Beware: This component is used in mailer content, so be mindful of email markup compatibility %> | ||
| <%= content_tag( | ||
| :div, | ||
| role: 'figure', | ||
| 'aria-labelledby': barcode_caption_id, | ||
| class: css_class, | ||
| **tag_options, | ||
| ) do %> | ||
| <%= barcode_html.html_safe %> | ||
| <div id="<%= barcode_caption_id %>" class="text-center margin-top-1"> | ||
| <% if label.present? %> | ||
| <span class="usa-sr-only"><%= label %>:</span> | ||
| <% end %> | ||
| <%= formatted_data %> | ||
| </div> | ||
| <% end %> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| require 'barby' | ||
| require 'barby/barcode/code_128' | ||
| require 'barby/outputter/html_outputter' | ||
|
|
||
| class BarcodeComponent < BaseComponent | ||
| attr_reader :barcode_data, :label, :label_formatter, :tag_options | ||
|
|
||
| def initialize(barcode_data:, label:, label_formatter: nil, **tag_options) | ||
| @barcode_data = barcode_data | ||
| @label = label | ||
| @label_formatter = label_formatter | ||
| @tag_options = tag_options | ||
| end | ||
|
|
||
| def formatted_data | ||
| formatted_data = barcode_data | ||
| formatted_data = label_formatter.call(formatted_data) if label_formatter | ||
| formatted_data | ||
| end | ||
|
|
||
| def barcode_html | ||
| html = Barby::Code128.new(barcode_data).to_html(class_name: 'barcode') | ||
| # The Barby gem doesn't provide much control over rendered output, so we need to manually slice | ||
| # in accessibility features (label as substitute to illegible inner content). | ||
| html.gsub( | ||
| '><tbody>', | ||
| %( aria-label="#{t('components.barcode.table_label')}"><tbody aria-hidden="true">), | ||
| ) | ||
| end | ||
|
|
||
| def barcode_caption_id | ||
| "barcode-caption-#{unique_id}" | ||
| end | ||
|
|
||
| def css_class | ||
| [*tag_options[:class], 'display-inline-block margin-0'] | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,31 +1,19 @@ | ||||||||||||||||||||||||||||||||||||||||||
| require 'barby' | ||||||||||||||||||||||||||||||||||||||||||
| require 'barby/barcode/code_128' | ||||||||||||||||||||||||||||||||||||||||||
| require 'barby/outputter/png_outputter' | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| module Idv | ||||||||||||||||||||||||||||||||||||||||||
| module InPerson | ||||||||||||||||||||||||||||||||||||||||||
| class ReadyToVerifyPresenter | ||||||||||||||||||||||||||||||||||||||||||
| # WILLFIX: With LG-6881, confirm timezone or use deadline from enrollment response. | ||||||||||||||||||||||||||||||||||||||||||
| USPS_SERVER_TIMEZONE = ActiveSupport::TimeZone['America/New_York'] | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| delegate :selected_location_details, to: :enrollment | ||||||||||||||||||||||||||||||||||||||||||
| delegate :selected_location_details, :enrollment_code, to: :enrollment | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def initialize(enrollment:) | ||||||||||||||||||||||||||||||||||||||||||
| @enrollment = enrollment | ||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def barcode_data_url | ||||||||||||||||||||||||||||||||||||||||||
| "data:image/png;base64,#{Base64.strict_encode64(barcode_image_data)}" | ||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def formatted_due_date | ||||||||||||||||||||||||||||||||||||||||||
| due_date.in_time_zone(USPS_SERVER_TIMEZONE).strftime(I18n.t('time.formats.event_date')) | ||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def formatted_enrollment_code | ||||||||||||||||||||||||||||||||||||||||||
| EnrollmentCodeFormatter.format(enrollment_code) | ||||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def selected_location_hours(prefix) | ||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The body of this method should change to the below, to accommodate the difference in format of hours = selected_location_details["#{prefix}Hours"]
return localized_hours(hours) if hoursThis is also done here in PR #6624.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, if I make those changes here before #6624 is merged, then it would break the page rendering for "Ready to verify"? 🤔 I guess I can plug the same changes noted previously into this code: identity-idp/app/controllers/api/verify/password_confirm_controller.rb Lines 101 to 120 in 17d7e30
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tomas-nava Yeah, there's a lot from #6624 that I'd have to pull into this branch to be able to use the updated selected location shape. Could we merge this without those and update #6624? Or, conversely, merge #6624 and I'll update this one?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||||||
| selected_location_details['hours'].each do |hours_candidate| | ||||||||||||||||||||||||||||||||||||||||||
| hours = hours_candidate["#{prefix}Hours"] | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -40,7 +28,6 @@ def needs_proof_of_address? | |||||||||||||||||||||||||||||||||||||||||
| private | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| attr_reader :enrollment | ||||||||||||||||||||||||||||||||||||||||||
| delegate :enrollment_code, to: :enrollment | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def barcode_image_data | ||||||||||||||||||||||||||||||||||||||||||
| Barby::Code128C.new(enrollment_code).to_png(margin: 0, xdim: 2) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| <p> | ||
| <%= t('user_mailer.in_person_ready_to_verify.greeting', name: @first_name) %><br> | ||
| <%= t('user_mailer.in_person_ready_to_verify.intro') %> | ||
| </p> | ||
|
|
||
| <table class="info-alert margin-y-4"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to make the alert heading:
I think this is one way to introduce some consistency in style between the email and the Login page.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The font size difference is present in the Figma designs (18px for bolded heading, 16px for unbolded text). It'd be easy enough for me to standardize them as the same body font size though if that's what we want.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see how it's a bit more noticeable a difference to control these font sizes in the email template though, since the default body font size is 13px in the emails (vs. 16px elsewhere in the app). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is a good point. Might be worth the design team looking at the email styling after pilot. |
||
| <tr> | ||
| <td width="16"> | ||
| <%= image_tag('email/info.png', width: 16, height: 16, alt: '') %> | ||
| </td> | ||
| <td> | ||
| <p class="margin-bottom-1"><strong><%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %></strong></p> | ||
| <p class="margin-bottom-0"><%= t('in_person_proofing.body.barcode.deadline_restart') %></p> | ||
| </td> | ||
| </tr> | ||
| </table> | ||
|
|
||
| <div class="border-1px border-primary-light radius-lg padding-4"> | ||
| <h2 class="margin-top-0 margin-bottom-2 font-heading-lg text-bold"> | ||
| <%= t('in_person_proofing.body.barcode.items_to_bring') %> | ||
| </h2> | ||
| <p><%= t('in_person_proofing.body.barcode.emailed_info') %></p> | ||
| <table class="process-list"> | ||
| <tr> | ||
| <td><div class="process-list__circle">1</div></td> | ||
| <td> | ||
| <h3 class="font-heading-md text-bold"><%= t('in_person_proofing.process.barcode.heading') %></h3> | ||
| <p><%= t('in_person_proofing.process.barcode.info') %></p> | ||
| <%= render BarcodeComponent.new( | ||
| barcode_data: @presenter.enrollment_code, | ||
| label: nil, | ||
| label_formatter: Idv::InPerson::EnrollmentCodeFormatter.method(:format), | ||
| ) %> | ||
| </td> | ||
| </tr> | ||
| <tr> | ||
| <td><div class="process-list__circle">2</div></td> | ||
| <td> | ||
| <h3 class="font-heading-md text-bold"><%= t('in_person_proofing.process.state_id.heading') %></h3> | ||
| <p class="margin-bottom-105"><%= t('in_person_proofing.process.state_id.info') %></p> | ||
| <ul class="usa-list margin-y-105"> | ||
| <% t('in_person_proofing.process.state_id.acceptable_documents').each do |document| %> | ||
| <li><%= document %></li> | ||
| <% end %> | ||
| </ul> | ||
| <p><%= t('in_person_proofing.process.state_id.no_other_documents') %></p> | ||
| </td> | ||
| </tr> | ||
| <% if @presenter.needs_proof_of_address? %> | ||
| <tr> | ||
| <td><div class="process-list__circle">4</div></td> | ||
| <td> | ||
| <h3 class="font-heading-md text-bold"><%= t('in_person_proofing.process.proof_of_address.heading') %></h3> | ||
| <p class="margin-bottom-105"><%= t('in_person_proofing.process.proof_of_address.info') %></p> | ||
| <ul class="usa-list margin-y-105"> | ||
| <% t('in_person_proofing.process.proof_of_address.acceptable_proof').each do |proof| %> | ||
| <li><%= proof %></li> | ||
| <% end %> | ||
| </ul> | ||
| </td> | ||
| </tr> | ||
| <% end %> | ||
| </table> | ||
| <p class="margin-bottom-0"> | ||
| <%= t('in_person_proofing.body.barcode.items_to_bring_questions') %> | ||
| <%= link_to( | ||
| t('in_person_proofing.body.barcode.learn_more'), | ||
| MarketingSite.help_center_article_url( | ||
| category: 'verify-your-identity', | ||
| article: 'how-to-verify-in-person', | ||
| ), | ||
| ) %> | ||
| </p> | ||
| </div> | ||
|
|
||
|
aduth marked this conversation as resolved.
|
||
| <% if @presenter.selected_location_details.present? %> | ||
| <div class="margin-y-4"> | ||
| <h2 class="font-sans-md margin-bottom-1 text-normal text-bold"><%= @presenter.selected_location_details['name'] %></h2> | ||
| <div class="margin-bottom-1"> | ||
| <%= @presenter.selected_location_details['streetAddress'] %><br> | ||
| <%= @presenter.selected_location_details['city'] %>, | ||
| <%= @presenter.selected_location_details['state'] %> | ||
| <%= @presenter.selected_location_details['zip5'] %>-<%= @presenter.selected_location_details['zip4'] %> | ||
| </div> | ||
| <div><strong><%= t('in_person_proofing.body.barcode.retail_hours') %></strong></div> | ||
| <div class="margin-bottom-2"> | ||
| <%= t('date.range', from: t('date.day_names')[0], to: t('date.day_names')[4]) %>: <%= @presenter.selected_location_hours(:weekday) %><br> | ||
| <%= t('date.day_names')[5] %>: <%= @presenter.selected_location_hours(:saturday) %><br> | ||
| <%= t('date.day_names')[6] %>: <%= @presenter.selected_location_hours(:sunday) %> | ||
| </div> | ||
| <div> | ||
| <%= @presenter.selected_location_details[:phone] %> | ||
| </div> | ||
| </div> | ||
| <% end %> | ||
|
|
||
| <p><%= t('in_person_proofing.body.barcode.speak_to_associate') %></p> | ||
|
|
||
| <p> | ||
| <strong><%= t('in_person_proofing.body.barcode.deadline', deadline: @presenter.formatted_due_date) %></strong> | ||
| <%= t('in_person_proofing.body.barcode.no_appointment_required') %> | ||
| </p> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| --- | ||
| en: | ||
| components: | ||
| barcode: | ||
| table_label: Barcode | ||
| clipboard_button: | ||
| label: Copy | ||
| javascript_required: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| --- | ||
| es: | ||
| components: | ||
| barcode: | ||
| table_label: Código de barras | ||
| clipboard_button: | ||
| label: Copiar | ||
| javascript_required: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| --- | ||
| fr: | ||
| components: | ||
| barcode: | ||
| table_label: Code-barres | ||
| clipboard_button: | ||
| label: Copier | ||
| javascript_required: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.