Skip to content

Commit 73da1ec

Browse files
asiisiinanotone
andauthored
Nanotone/overflow table layout (#21648)
* Refactor ExtrasGeneratorV2 to handle list-and-loops better * Remove top_level_key from HashConverter specs * Fix expand_collection tests * Fix subquestion-sorting bug per code review * Fix some merge conflicts * Build out table layout for overflow page redesign * Make 21-0781V2 overflow fixture more realistic for redesign layouting * Update PDF test fixtures for old and new overflow pages * Fix tests * fix faling tests and add italic tag for no response text * fix linting issue --------- Co-authored-by: Yang Yang <yangyang@navapbc.com>
1 parent 41200a8 commit 73da1ec

File tree

11 files changed

+92
-59
lines changed

11 files changed

+92
-59
lines changed

lib/pdf_fill/extras_generator_v2.rb

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ class ExtrasGeneratorV2 < ExtrasGenerator
1010
class Question
1111
attr_accessor :section_index, :overflow
1212

13-
def initialize(metadata)
13+
def initialize(question_text, metadata)
1414
@section_index = nil
1515
@number = metadata[:question_num]
16+
@text = question_text
1617
@subquestions = []
1718
@overflow = false
1819
end
@@ -28,50 +29,60 @@ def sorted_subquestions
2829
end
2930
end
3031

31-
def render(pdf, list_format: false)
32-
sorted_subquestions.each do |subq|
33-
value = subq[:value].to_s.gsub('\n', '<br/>')
32+
def sorted_subquestions_markup
33+
sorted_subquestions.map do |subq|
3434
metadata = subq[:metadata]
35-
prefix = "#{metadata[:question_num]}#{metadata[:question_suffix]}. #{metadata[:question_text].humanize}"
36-
i = metadata[:i]
37-
prefix += " Line #{i + 1}" if i.present?
38-
39-
if list_format
40-
pdf.markup("<p>#{prefix}: <b>#{value}</b></p>")
41-
else
42-
pdf.markup("<p>#{prefix}:</p>")
43-
pdf.markup("<b>#{value}</b>")
44-
end
35+
label = metadata[:question_label].presence || metadata[:question_text]
36+
value = subq[:value].to_s.gsub("\n", '<br/>')
37+
value = "<i>#{value}</i>" if value == 'no response'
38+
"<tr><td style='width:91'>#{label}:</td><td>#{value}</td></tr>"
4539
end
4640
end
41+
42+
def render(pdf, list_format: false)
43+
pdf.markup("<h3>#{@number}. #{@text}</h3>") unless list_format
44+
pdf.markup(['<table>', sorted_subquestions_markup, '</table>'].flatten.join, text: { margin_bottom: 10 })
45+
end
4746
end
4847

4948
class ListQuestion < Question
50-
def initialize(metadata)
49+
def initialize(question_text, metadata)
5150
super
51+
@item_label = metadata[:item_label]
5252
@items = []
53-
@array_question_text = metadata[:array_question_text]
5453
end
5554

5655
def add_text(value, metadata)
5756
@overflow ||= metadata.fetch(:overflow, true)
5857
i = metadata[:i]
59-
@items[i] ||= Question.new(metadata)
58+
@items[i] ||= Question.new(nil, metadata)
6059
@items[i].add_text(value, metadata)
6160
end
6261

6362
def render(pdf)
64-
pdf.markup("<h4>#{@number}. #{@array_question_text}</h4>")
65-
@items.each do |question|
63+
pdf.markup("<h3>#{@number}. #{@text}</h3>")
64+
@items.each.with_index(1) do |question, index|
65+
pdf.markup(
66+
"<table><tr><th><i>#{@item_label} #{index}</i></th></tr></table>",
67+
table: {
68+
cell: {
69+
borders: [:bottom],
70+
border_width: 1,
71+
padding: [5, 0, 3.5, 0]
72+
}
73+
},
74+
text: { margin_bottom: -2 }
75+
)
6676
question.render(pdf, list_format: true)
6777
end
6878
end
6979
end
7080

71-
def initialize(form_name: nil, submit_date: nil, start_page: 1, sections: nil)
81+
def initialize(form_name: nil, submit_date: nil, question_key: nil, start_page: 1, sections: nil)
7282
super()
7383
@form_name = form_name
7484
@submit_date = submit_date
85+
@question_key = question_key
7586
@start_page = start_page
7687
@sections = sections
7788
@questions = {}
@@ -86,7 +97,8 @@ def set_font(pdf)
8697
def add_text(value, metadata)
8798
question_num = metadata[:question_num]
8899
if @questions[question_num].blank?
89-
@questions[question_num] = (metadata[:i].blank? ? Question : ListQuestion).new(metadata)
100+
question_text = @question_key[question_num]
101+
@questions[question_num] = (metadata[:i].blank? ? Question : ListQuestion).new(question_text, metadata)
90102
end
91103
@questions[question_num].add_text(value, metadata)
92104
end
@@ -200,15 +212,18 @@ def register_source_sans_font(pdf)
200212

201213
def set_markup_options(pdf)
202214
pdf.markup_options = {
203-
heading2: { style: :normal, size: 13, margin_top: 12 },
204-
heading3: { style: :bold, size: 10.5, margin_top: 10 },
205-
heading4: { style: :normal, size: 10.5 },
215+
heading2: { style: :normal, size: 13, margin_top: 12, margin_bottom: -4 },
216+
heading3: { style: :bold, size: 10.5, margin_top: 10, margin_bottom: -2 },
206217
table: {
207218
cell: {
208219
border_width: 0,
209-
padding: [2, 0, 2, 0]
220+
padding: [1, 0, 1, 0]
210221
}
211222
},
223+
text: {
224+
leading: 0.5,
225+
size: 10.5
226+
},
212227
list: { bullet: { char: '✓', margin: 0 }, content: { margin: 4 }, vertical_margin: 0 }
213228
}
214229
end

lib/pdf_fill/filler.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def make_hash_converter(form_id, form_class, submit_date, fill_options)
176176
ExtrasGeneratorV2.new(
177177
form_name: form_id.sub(/V2\z/, ''),
178178
submit_date:,
179+
question_key: form_class::QUESTION_KEY,
179180
start_page: form_class::START_PAGE,
180181
sections: form_class::SECTIONS
181182
)

lib/pdf_fill/forms/form_base.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class FormBase
99

1010
START_PAGE = 1
1111
SECTIONS = nil
12+
QUESTION_KEY = nil
1213

1314
def self.date_strftime
1415
'%m/%d/%Y'

lib/pdf_fill/forms/va210781v2.rb

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,23 @@ class Va210781v2 < FormBase
2222
limit: 12, # limit: 28 (with combs removed)
2323
question_num: 1,
2424
question_suffix: 'A',
25+
question_label: 'First',
2526
question_text: 'VETERAN/SERVICE MEMBER\'S NAME. First Name'
2627
},
2728
'middleInitial' => {
2829
key: 'F[0].#subform[2].VeteransMiddleInitial1[0]',
2930
limit: 1,
3031
question_num: 1,
3132
question_suffix: 'B',
33+
question_label: 'Middle Initial',
3234
question_text: 'VETERAN/SERVICE MEMBER\'S NAME. Middle Initial'
3335
},
3436
'last' => {
3537
key: 'F[0].#subform[2].VeteransLastName[0]',
3638
limit: 18, # limit: 45 (with combs removed)
3739
question_num: 1,
3840
question_suffix: 'C',
41+
question_label: 'Last',
3942
question_text: 'VETERAN/SERVICE MEMBER\'S NAME. Last Name'
4043
}
4144
},
@@ -143,6 +146,7 @@ class Va210781v2 < FormBase
143146
'events' => {
144147
limit: 6,
145148
first_key: 'details',
149+
item_label: 'Event',
146150
question_text: 'Traumatic event(s) information',
147151
question_num: 9,
148152
'details' => {
@@ -538,6 +542,7 @@ class Va210781v2 < FormBase
538542
'treatmentProvidersDetails' => {
539543
limit: 3,
540544
first_key: 'facilityInfo',
545+
item_label: 'Treatment facility',
541546
question_text: 'TREATMENT INFORMATION',
542547
question_num: 13,
543548
'facilityInfo' => {
@@ -628,39 +633,48 @@ class Va210781v2 < FormBase
628633
}.freeze
629634
# rubocop:enable Layout/LineLength
630635

636+
QUESTION_KEY = {
637+
1 => 'Veteran/Service member\'s name',
638+
2 => 'Social security number',
639+
3 => 'VA file number',
640+
4 => 'Date of birth',
641+
5 => 'Veteran\'s service number',
642+
6 => 'Telephone number',
643+
7 => 'Email address',
644+
8 => 'Type of in-service traumatic event(s)',
645+
9 => 'Traumatic event(s) information',
646+
10 => 'Behavioral Changes Following In-service Personal Traumatic Event(s)',
647+
11 => 'Was an official report filed?',
648+
12 => 'Possible sources of evidence following the traumatic event(s)',
649+
13 => 'Treatment information',
650+
14 => 'Remarks',
651+
16 => 'Veteran/service member\'s signature'
652+
}.freeze
653+
631654
SECTIONS = [
632655
{
633656
label: 'Section I: Veteran\'s Identification Information',
634-
question_nums: (1..7).to_a,
635-
top_level_keys: %w[
636-
veteranFullName vaFileNumber veteranDateOfBirth veteranServiceNumber veteranPhone veteranIntPhone
637-
email emailOverflow
638-
]
657+
question_nums: (1..7).to_a
639658
},
640659
{
641660
label: 'Section II: Traumatic Event(s) Information',
642-
question_nums: [8, 9],
643-
top_level_keys: ['events']
661+
question_nums: [8, 9]
644662
},
645663
{
646664
label: 'Section III: Additional Information Associated with the In-service Traumatic Event(s)',
647-
question_nums: [10, 11, 12],
648-
top_level_keys: %w[behaviors behaviorsDetails reportsDetails evidence]
665+
question_nums: [10, 11, 12]
649666
},
650667
{
651668
label: 'Section IV: Treatment Information',
652-
question_nums: [13],
653-
top_level_keys: ['treatmentProvidersDetails']
669+
question_nums: [13]
654670
},
655671
{
656672
label: 'Section V: Remarks',
657-
question_nums: [14],
658-
top_level_keys: %w[additionalInformation additionalInformationOverflow]
673+
question_nums: [14]
659674
},
660675
{
661676
label: 'Section VII: Certification and Signature',
662-
question_nums: [15],
663-
top_level_keys: %w[signature signatureDate]
677+
question_nums: [15]
664678
}
665679
].freeze
666680

lib/pdf_fill/hash_converter.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,16 @@ def overflow?(key_data, value, from_array_overflow = false)
6464

6565
def add_to_extras(key_data, v, i, overflow: true, array_key_data: nil)
6666
return if v.blank? || key_data.nil?
67-
return if key_data[:question_num].blank? || key_data[:question_text].blank?
67+
return if key_data[:question_num].blank? || (key_data[:question_text].blank? && key_data[:question_label].blank?)
6868

6969
i = nil if key_data[:skip_index]
7070
v = "$#{v}" if key_data[:dollar]
7171
v = v.extras_value if v.is_a?(PdfFill::FormValue)
72-
array_question_text = array_key_data.try(:[], :question_text)
72+
item_label = array_key_data.try(:[], :item_label)
7373
@extras_generator.add_text(
7474
v,
75-
key_data.slice(:question_num, :question_suffix, :question_text).merge(
76-
i:, overflow:, array_question_text:
75+
key_data.slice(:question_num, :question_suffix, :question_text, :question_label).merge(
76+
i:, overflow:, item_label:
7777
)
7878
)
7979
end

spec/fixtures/pdf_fill/21-0781V2/overflow.json

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"vaFileNumber": "12345678",
33
"veteranSocialSecurityNumber": "123456789",
44
"veteranFullName": {
5-
"first": "XXXXXXXXXXXXX",
6-
"middle": "Tester",
7-
"last": "XXXXXXXXXXXXXXXXXX"
5+
"first": "Laura",
6+
"middle": "J",
7+
"last": "Rodriguez-Wittgenstein"
88
},
99
"veteranDateOfBirth": "1981-11-05",
1010
"veteranServiceNumber": "987654321",
@@ -20,8 +20,8 @@
2020
},
2121
"events": [
2222
{
23-
"details": "Lorem ipsum dolor sit amet.",
24-
"location": "abcdefghijklmn opqrstuvwxyz1234a bpqrstuvwxyz1234a",
23+
"details": "Corpsman on medical ship in Da Nang harbor, Vietnam",
24+
"location": "Stationed on U.S.S. XYZ",
2525
"timing": "Summer of '70",
2626
"otherReports": { "police": true },
2727
"agency": "SVI",
@@ -31,15 +31,15 @@
3131
"country": "USA"
3232
},
3333
{
34-
"details": "Lorem ipsum dolor sit amet.",
35-
"location": "abcdefghijklmn opqrstuvwxyz1234a bpqrstuvwxyz1234a",
34+
"details": "Mugged",
35+
"location": "Back alley in Big Town, USA",
3636
"timing": "June 2007",
3737
"unlistedReport": "incident report"
3838
},
3939
{
40-
"details": "Lorem ipsum dolor sit amet..",
41-
"location": "abcdefghijklmn opqrstuvwxyz1234a bpqrstuvwxyz1234a",
42-
"timing": "February 14, 2020",
40+
"details": "I would be minding my own business and this other soldier would use his rank to force me to do push ups and sit ups and other stuff even when we were off duty.\nIf I refused the next day would be worse during work hours and he would like to the chain of command that I had done something wrong. He would harass and belittle me. I tried to tell someone but nobody cared, I would just get in more trouble.",
41+
"location": "Fort Belvior, VA",
42+
"timing": "June 2007",
4343
"militaryReports": { "restricted": true }
4444
},
4545
{
@@ -124,6 +124,7 @@
124124
"noDates": true
125125
}
126126
],
127+
"additionalInformation": "The traumatic event I experienced during my service has had a profound and lasting impact on my mental health. Since the incident, I have struggled with symptoms of Post-Traumatic Stress Disorder (PTSD), depression, and anxiety, which have significantly affected my daily life and well-being.\nAfter the event, I began to notice intense feelings of fear and helplessness whenever I was reminded of the experience. These flashbacks were frequent and uncontrollable, often triggered by loud noises, crowded places, or even certain smells. The emotional distress caused by these flashbacks would leave me feeling overwhelmed, panicked, and unable to function. At times, it felt as though I was reliving the traumatic experience, and I had difficulty distinguishing the past from the present.\nI also developed chronic insomnia. I found it difficult to fall asleep, and when I did manage to sleep, I was frequently awakened by nightmares of the traumatic event. These disturbed nights left me feeling exhausted and unable to perform basic tasks during the day. The lack of rest contributed to a decline in my physical health, as I struggled with fatigue, headaches, and an overall sense of lethargy.\nSocially, I became increasingly withdrawn. I avoided interactions with friends, family, and even fellow service members, as I felt disconnected and unable to trust anyone. My relationships suffered as I became irritable, short-tempered, and emotionally distant. I found it hard to experience joy or satisfaction in anything, including activities I once enjoyed, such as hobbies and socializing.\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
127128
"optionIndicator": "notEnrolled",
128129
"signatureDate": "2016-01-31"
129130
}
56 Bytes
Binary file not shown.
7.05 KB
Binary file not shown.
25.1 KB
Binary file not shown.

spec/lib/pdf_fill/extras_generator_v2_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
describe PdfFill::ExtrasGeneratorV2::Question do
1212
subject do
13-
question = described_class.new(add_text_calls.first[1])
13+
question = described_class.new('First name', add_text_calls.first[1])
1414
add_text_calls.each { |call| question.add_text(*call) }
1515
question
1616
end
@@ -47,7 +47,7 @@
4747
end
4848

4949
it 'populates section indices correctly' do
50-
questions = [1, 9, 42, 7].index_with { |question_num| described_class::Question.new(question_num:) }
50+
questions = [1, 9, 42, 7].index_with { |question_num| described_class::Question.new(nil, question_num:) }
5151
subject.instance_variable_set(:@questions, questions)
5252
subject.populate_section_indices!
5353
indices = subject.instance_variable_get(:@questions).values.map(&:section_index)

0 commit comments

Comments
 (0)