Convert datetime field to datetime_local (#8572)

* Convert datetime field to datetime_local

* Fix tests

* Add value formatting view datetime component

* Add helper datetime component value
This commit is contained in:
Damien Le Thiec 2023-02-09 15:18:38 +01:00 committed by GitHub
parent 9c26d76f28
commit 4b0e6ea382
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 66 deletions

View file

@ -173,6 +173,7 @@
input[type=email],
input[type=password],
input[type=date],
input[type=datetime-local],
input[type=number],
input[type=tel],
textarea,
@ -207,6 +208,7 @@
input[type=date],
input[type=number],
input[type=tel],
input[type=datetime-local],
textarea,
select {
border-radius: 4px;
@ -248,6 +250,7 @@
input[type=password],
input[type=date],
input[type=number],
input[type=datetime-local],
input[type=tel],
textarea {
@media (max-width: $two-columns-breakpoint) {
@ -284,7 +287,8 @@
&:not([size]) {
&[type='date'],
&[type='tel'],
&[type='number'] {
&[type='number'],
&[type='datetime-local'] {
width: 33.33%;
}

View file

@ -1,9 +1,10 @@
class EditableChamp::DatetimeComponent < EditableChamp::EditableChampBaseComponent
def datetime_start_year(date)
if date == nil || date.year == 0 || date.year >= Date.today.year - 1
Date.today.year - 1
def formatted_value_for_datetime_locale
if @champ.valid? && @champ.value.present?
# convert to a format that the datetime-local input can understand
DateTime.iso8601(@champ.value).strftime('%Y-%m-%dT%H:%M')
else
date.year
@champ.value
end
end
end

View file

@ -1,4 +1,2 @@
- parsed_value = @champ.value.present? ? Time.zone.parse(@champ.value) : nil
.datetime
= @form.datetime_select(:value, id: @champ.input_id, aria: { describedby: @champ.describedby_id }, selected: parsed_value, start_year: datetime_start_year(parsed_value), end_year: Date.today.year + 50, minute_step: 5, include_blank: true)
= @form.datetime_field(:value, value: formatted_value_for_datetime_locale, id: @champ.input_id, aria: { describedby: @champ.describedby_id })

View file

@ -36,10 +36,6 @@ class Champs::DatetimeChamp < Champ
value.present? ? I18n.l(Time.zone.parse(value)) : ""
end
def html_label?
false
end
private
def convert_to_iso8601

View file

@ -0,0 +1,27 @@
describe EditableChamp::DatetimeComponent, type: :component do
let(:component) {
described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:)
}
describe '#formatted_value_for_datetime_locale' do
subject { component.formatted_value_for_datetime_locale }
context 'when the value is nil' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: nil) }
it { is_expected.to be_nil }
end
context 'when the value is not a valid datetime' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: 'invalid') }
it { is_expected.to be_nil }
end
context 'when the value is a valid datetime' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: '2020-01-01T00:00:00+01:00') }
it { is_expected.to eq('2020-01-01T00:00') }
end
end
end

View file

@ -796,11 +796,7 @@ describe Instructeurs::DossiersController, type: :controller do
},
'1': {
id: champ_datetime.id,
'value(1i)': 2019,
'value(2i)': 12,
'value(3i)': 21,
'value(4i)': 13,
'value(5i)': 17
value: '2019-12-21T13:17'
},
'2': {
id: champ_linked_drop_down_list.id,

View file

@ -18,5 +18,6 @@ shared_examples "the user has got a prefilled dossier, owned by themselves" do
expect(page).to have_field(type_de_champ_text.libelle, with: text_value)
expect(page).to have_field(type_de_champ_phone.libelle, with: phone_value)
expect(page).to have_css('label', text: type_de_champ_phone.libelle)
expect(page).to have_field(type_de_champ_datetime.libelle, with: datetime_value)
end
end

View file

@ -21,8 +21,9 @@ describe 'The user' do
# fill data
fill_in('text *', with: 'super texte')
fill_in('textarea', with: 'super textarea')
fill_in('date', with: '12-12-2012')
select_date_and_time(Time.zone.parse('06/01/2030 7h05'), form_id_for_datetime('datetime'))
fill_in('date *', with: '12-12-2012')
fill_in('datetime', with: Time.zone.parse('2023-01-06T07:05'))
find("input[type=datetime-local]").send_keys(:arrow_up).send_keys(:arrow_down) # triggers onChange
fill_in('number', with: '42')
fill_in('decimal_number', with: '17')
fill_in('integer_number', with: '12')
@ -57,7 +58,7 @@ describe 'The user' do
expect(champ_value_for('text')).to eq('super texte')
expect(champ_value_for('textarea')).to eq('super textarea')
expect(champ_value_for('date')).to eq('2012-12-12')
expect(champ_value_for('datetime')).to eq('2030-01-06T07:05:00+01:00')
expect(champ_value_for('datetime')).to eq('2023-01-06T07:05:00+01:00')
expect(champ_value_for('number')).to eq('42')
expect(champ_value_for('decimal_number')).to eq('17')
expect(champ_value_for('integer_number')).to eq('12')
@ -82,7 +83,7 @@ describe 'The user' do
expect(page).to have_field('text', with: 'super texte')
expect(page).to have_field('textarea', with: 'super textarea')
expect(page).to have_field('date', with: '2012-12-12')
check_date_and_time(Time.zone.parse('06/01/2030 7:05'), form_id_for_datetime('datetime'))
expect(page).to have_field('datetime', with: '2023-01-06T07:05')
expect(page).to have_field('number', with: '42')
expect(page).to have_checked_field('checkbox')
expect(page).to have_checked_field('Madame')
@ -527,32 +528,6 @@ describe 'The user' do
expect(page).to have_current_path(identite_dossier_path(user_dossier))
end
def form_id_for_datetime(libelle)
# The HTML for datetime is a bit specific since it has 5 selects, below here is a sample HTML
# So, we want to find the partial id of a datetime (partial because there are 5 ids:
# dossier_champs_attributes_3_value_1i, 2i, ... 5i) ; we are interested in the 'dossier_champs_attributes_3_value' part
# which is then completed in select_date_and_time and check_date_and_time
#
# We find the H2, find the first select in the next .datetime div, then strip the last 3 characters
#
# <h4 class="form-label">
# libelle
# </h4>
# <div class="datetime">
# <span class="hidden">
# <label for="dossier_champs_attributes_3_value_3i">Jour</label></span>
# <select id="dossier_champs_attributes_3_value_3i" name="dossier[champs_attributes][3][value(3i)]">
# <option value=""></option>
# <option value="1">1</option>
# <option value="2">2</option>
# <!-- … -->
# </select>
# <!-- … 4 other selects for month, year, minute and seconds -->
# </div>
e = find(:xpath, ".//div[contains(text()[normalize-space()], '#{libelle}')]")
e.sibling('.datetime').first('select')[:id][0..-4]
end
def champ_value_for(libelle)
champs = user_dossier.reload.champs_public
champs.find { |c| c.libelle == libelle }.value
@ -565,20 +540,4 @@ describe 'The user' do
click_on 'Continuer'
expect(page).to have_current_path(brouillon_dossier_path(user_dossier))
end
def select_date_and_time(date, field)
select date.strftime('%Y'), from: "#{field}_1i" # year
select I18n.l(date, format: '%B'), from: "#{field}_2i" # month
select date.strftime('%-d'), from: "#{field}_3i" # day
select date.strftime('%H'), from: "#{field}_4i" # hour
select date.strftime('%M'), from: "#{field}_5i" # minute
end
def check_date_and_time(date, field)
expect(page).to have_selected_value("#{field}_1i", selected: date.strftime('%Y'))
expect(page).to have_selected_value("#{field}_2i", selected: I18n.l(date, format: '%B'))
expect(page).to have_selected_value("#{field}_3i", selected: date.strftime('%-d'))
expect(page).to have_selected_value("#{field}_4i", selected: date.strftime('%H'))
expect(page).to have_selected_value("#{field}_5i", selected: date.strftime('%M'))
end
end

View file

@ -6,8 +6,10 @@ describe 'Prefilling a dossier (with a GET request):' do
let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) }
let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) }
let(:type_de_champ_datetime) { create(:type_de_champ_datetime, procedure: procedure) }
let(:text_value) { "My Neighbor Totoro is the best movie ever" }
let(:phone_value) { "invalid phone value" }
let(:datetime_value) { "2023-02-01T10:32" }
context 'when authenticated' do
it_behaves_like "the user has got a prefilled dossier, owned by themselves" do
@ -20,7 +22,8 @@ describe 'Prefilling a dossier (with a GET request):' do
visit commencer_path(
path: procedure.path,
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value,
"champ_#{type_de_champ_datetime.to_typed_id}" => datetime_value
)
click_on "Poursuivre mon dossier prérempli"
@ -33,7 +36,8 @@ describe 'Prefilling a dossier (with a GET request):' do
visit commencer_path(
path: procedure.path,
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value,
"champ_#{type_de_champ_datetime.to_typed_id}" => datetime_value
)
end

View file

@ -6,8 +6,10 @@ describe 'Prefilling a dossier (with a POST request):' do
let(:type_de_champ_text) { create(:type_de_champ_text, procedure: procedure) }
let(:type_de_champ_phone) { create(:type_de_champ_phone, procedure: procedure) }
let(:type_de_champ_datetime) { create(:type_de_champ_datetime, procedure: procedure) }
let(:text_value) { "My Neighbor Totoro is the best movie ever" }
let(:phone_value) { "invalid phone value" }
let(:datetime_value) { "2023-02-01T10:32" }
scenario "the user get the URL of a prefilled orphan brouillon dossier" do
dossier_url = create_and_prefill_dossier_with_post_request
@ -95,7 +97,8 @@ describe 'Prefilling a dossier (with a POST request):' do
headers: { "Content-Type" => "application/json" },
params: {
"champ_#{type_de_champ_text.to_typed_id}" => text_value,
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value
"champ_#{type_de_champ_phone.to_typed_id}" => phone_value,
"champ_#{type_de_champ_datetime.to_typed_id}" => datetime_value
}.to_json
JSON.parse(session.response.body)["dossier_url"].gsub("http://www.example.com", "")
end