diff --git a/Gemfile b/Gemfile index d32c267f9..4c28d3619 100644 --- a/Gemfile +++ b/Gemfile @@ -36,7 +36,6 @@ gem 'omniauth' gem 'omniauth-github' gem 'omniauth-rails_csrf_protection' gem 'pg' -gem 'pickadate-rails' gem 'premailer-rails' gem 'pundit' diff --git a/Gemfile.lock b/Gemfile.lock index 3624f8f5e..535c1d98c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -352,8 +352,6 @@ GEM pg (1.6.3-arm64-darwin) pg (1.6.3-x86_64-darwin) pg (1.6.3-x86_64-linux) - pickadate-rails (3.5.6.1) - railties (>= 3.1.0) playwright-ruby-client (1.61.0) base64 concurrent-ruby (>= 1.1.6) @@ -666,7 +664,6 @@ DEPENDENCIES pagy (~> 43.6) parallel_tests pg - pickadate-rails premailer-rails pry-byebug pry-rails @@ -847,7 +844,6 @@ CHECKSUMS pg (1.6.3-arm64-darwin) sha256=7240330b572e6355d7c75a7de535edb5dfcbd6295d9c7777df4d9dddfb8c0e5f pg (1.6.3-x86_64-darwin) sha256=ee2e04a17c0627225054ffeb43e31a95be9d7e93abda2737ea3ce4a62f2729d6 pg (1.6.3-x86_64-linux) sha256=5d9e188c8f7a0295d162b7b88a768d8452a899977d44f3274d1946d67920ae8d - pickadate-rails (3.5.6.1) sha256=b10a91fe2c2c2695d15593fc4927068aba779cdea30537350a75da98f45f169d playwright-ruby-client (1.61.0) sha256=1f5c5f0307a2f6bd70b4fa797020a30eef5680caf8d5bd9ccc8d3937f6666e08 popper_js (2.11.8) sha256=f4b0be717fc0d50bdb3dbbc55788525a9e0e8f640b76c9971fc34ee609eadbd2 pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 5cc0d43c8..964776723 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,10 +16,7 @@ //= require rails-ujs //= require activestorage //= require chosen.jquery -//= require feedback-rating -//= require pickadate/picker -//= require pickadate/picker.date -//= require pickadate/picker.time +//= require 'jsimple-star-rating.min.js' //= require subscriptions-toggle //= require add-all-chapters //= require invitations @@ -31,16 +28,6 @@ $(function() { $("body").removeClass("no-js"); - $('#event_local_date, #meeting_local_date, #workshop_local_date, #workshop_rsvp_open_local_date, #workshop_rsvp_close_local_date').pickadate({ - format: 'dd/mm/yyyy' - }); - $('#announcement_expires_at, #ban_expires_at').pickadate(); - $( - "#meeting_local_time, #meeting_local_end_time, #event_local_time, #event_local_end_time, #workshop_local_time, #workshop_local_end_time, #workshop_rsvp_open_local_time, #workshop_rsvp_close_local_time" - ).pickatime({ - format: "HH:i", - }); - // Chosen for all other selects (exclude TomSelect fields) // Chosen hides inputs and selects, which becomes problematic when they are // required: browser validation doesn't get shown to the user. diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 54e9f854d..71cbed7d0 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -11,9 +11,6 @@ *= require_self *= require font_awesome5 *= require main - *= require pickadate/classic - *= require pickadate/classic.date - *= require pickadate/classic.time *= require chosen */ diff --git a/app/views/admin/announcements/edit.html.haml b/app/views/admin/announcements/edit.html.haml index 823b0b485..097242a38 100644 --- a/app/views/admin/announcements/edit.html.haml +++ b/app/views/admin/announcements/edit.html.haml @@ -9,6 +9,6 @@ = f.association :groups, label_method: :to_s, label: 'Select groups' = f.input :message, input_html: { rows: 3 }, hint: raw(t('admin.shared.markdown_hint', link: link_to(t('admin.shared.markdown'), 'https://commonmark.org/help/'))) - = f.input :expires_at, as: :string + = f.input :expires_at, as: :string, input_html: { value: @announcement.expires_at.strftime('%Y-%m-%d'), type: :date } .text-right = f.button :button, :update, class: 'btn btn-primary' diff --git a/app/views/admin/announcements/new.html.haml b/app/views/admin/announcements/new.html.haml index a82cb3c3f..e14cbed8f 100644 --- a/app/views/admin/announcements/new.html.haml +++ b/app/views/admin/announcements/new.html.haml @@ -10,6 +10,6 @@ = f.input :all_groups, as: :boolean, checked_value: true, unchecked_value: false, label: 'Send to all groups' = f.input :message, input_html: { rows: 3 }, hint: raw(t('admin.shared.markdown_hint', link: link_to(t('admin.shared.markdown'), 'https://commonmark.org/help/'))) - = f.input :expires_at, as: :string + = f.input :expires_at, as: :string, input_html: { type: :date } .text-right = f.button :button, :create, class: 'btn btn-primary' diff --git a/app/views/admin/bans/new.html.haml b/app/views/admin/bans/new.html.haml index 8368200cc..1d7c7eccd 100644 --- a/app/views/admin/bans/new.html.haml +++ b/app/views/admin/bans/new.html.haml @@ -12,7 +12,7 @@ = f.input :reason, as: :select, collection: [ 'Violated attendance policy', 'Violated code of conduct', 'Violated attendance eligibility', 'Offensive behavior' ] = f.input :note, input_html: { rows: 3 } = f.input :explanation, input_html: { rows: 3 } - = f.input :expires_at, as: :string, required: true, label: 'Date', input_html: { data: { value: Time.zone.now+1.month } } + = f.input :expires_at, as: :string, required: true, label: 'Date', input_html: { value: (Time.zone.now + 1.month).strftime('%Y-%m-%d'), type: :date } = f.input :permanent, as: :boolean .text-right = f.button :button, t('.create'), class: 'btn btn-primary' diff --git a/app/views/admin/events/_form.html.haml b/app/views/admin/events/_form.html.haml index 8f1dcc77a..231089153 100644 --- a/app/views/admin/events/_form.html.haml +++ b/app/views/admin/events/_form.html.haml @@ -11,11 +11,11 @@ .col-12.col-md-6 = f.input :slug, placeholder: 'for URI, e.g. 24-pull-requests' .col-12 - = f.input :local_date, label: 'Date', as: :string, required: true, input_html: { data: { value: @event.date_and_time.try(:strftime, '%d/%m/%Y') } } + = f.input :local_date, label: 'Date', required: true, input_html: { value: @event.date_and_time.try(:strftime, '%Y-%m-%d'), type: :date } .col-12.col-md-6 - = f.input :local_time, label: 'Starts at', as: :string, required: true, input_html: { data: { value: @event.time.try(:strftime, '%H:%M') } } + = f.input :local_time, label: 'Starts at', required: true, input_html: { value: @event.time.try(:strftime, '%H:%M'), type: :time } .col-12.col-md-6 - = f.input :local_end_time, label: 'Ends at', as: :string, required: true, input_html: { data: { value: @event.ends_at.try(:strftime, '%H:%M') } } + = f.input :local_end_time, label: 'Ends at', required: true, input_html: { value: @event.ends_at.try(:strftime, '%H:%M'), type: :time } .col-12 .mb-3 %label.form-label{ for: "event_timezone" } Time zone diff --git a/app/views/admin/meetings/_form.html.haml b/app/views/admin/meetings/_form.html.haml index 9c7c97ca3..9b37d301f 100644 --- a/app/views/admin/meetings/_form.html.haml +++ b/app/views/admin/meetings/_form.html.haml @@ -10,11 +10,11 @@ .col-12.col-md-6 = f.input :slug, required: true .col-12.col-md-6 - = f.input :local_date, as: :string, required: true, input_html: { data: { value: @meeting.date_and_time.try(:strftime, '%d/%m/%Y') } } + = f.input :local_date, required: true, input_html: { value: @meeting.date_and_time.try(:strftime, '%Y-%m-%d'), type: :date } .col-12.col-md-6 - = f.input :local_time, label: 'Starts at', as: :string, required: true, input_html: { data: { value: @meeting.time.try(:strftime, '%H:%M') } } + = f.input :local_time, label: 'Starts at', required: true, input_html: { value: @meeting.time.try(:strftime, '%H:%M'), type: :time } .col-12.col-md-6 - = f.input :local_end_time, label: 'Ends at', as: :string, required: true, input_html: { data: { value: @meeting.ends_at.try(:strftime, '%H:%M') } } + = f.input :local_end_time, label: 'Ends at', required: true, input_html: { value: @meeting.ends_at.try(:strftime, '%H:%M'), type: :time } .col-12 = f.input :description, placeholder: 'Supports HTML', as: :text, input_html: { rows: 5 } .col-12 diff --git a/app/views/admin/workshops/_shared_form.html.haml b/app/views/admin/workshops/_shared_form.html.haml index 042c431b3..20fafb5f3 100644 --- a/app/views/admin/workshops/_shared_form.html.haml +++ b/app/views/admin/workshops/_shared_form.html.haml @@ -5,11 +5,11 @@ .col-12 = f.association :chapter, as: :select, collection: Chapter.available_to_user(current_user) .col-12 - = f.input :local_date, label: 'Date', as: :string, required: true, input_html: { data: { value: @workshop.date_and_time.try(:strftime, '%d/%m/%Y') } } + = f.input :local_date, label: 'Date', required: true, input_html: { value: @workshop.date_and_time.try(:strftime, '%Y-%m-%d'), type: :date } .col-12.col-md-6 - = f.input :local_time, label: 'Begins at', as: :string, required: true, input_html: { data: { value: @workshop.time.try(:strftime, '%H:%M') } } + = f.input :local_time, label: 'Begins at', required: true, input_html: { value: @workshop.time.try(:strftime, '%H:%M'), type: :time } .col-12.col-md-6 - = f.input :local_end_time, label: 'Ends at', as: :string, required: true, input_html: { data: { value: @workshop.ends_at.try(:strftime, '%H:%M') } } + = f.input :local_end_time, label: 'Ends at', required: true, input_html: { value: @workshop.ends_at.try(:strftime, '%H:%M'), type: :time } .col-12#host = f.input :host, as: :select, collection: Sponsor.all, include_blank: true, selected: (@workshop.host.id rescue '') .col-12 @@ -27,11 +27,11 @@ %p.small.text-muted= t('admin.workshop.form.rsvp_details') .row .col-12.col-md-6 - = f.input :rsvp_open_local_date, label: 'Open date', as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:strftime, '%d/%m/%Y') } } + = f.input :rsvp_open_local_date, label: 'Open date', input_html: { value: @workshop.rsvp_opens_at.try(:strftime, '%Y-%m-%d'), type: :date } .col-12.col-md-6 - = f.input :rsvp_open_local_time, label: 'Open time', as: :string, input_html: { data: { value: @workshop.rsvp_opens_at.try(:time).try(:strftime, '%H:%M') } } + = f.input :rsvp_open_local_time, label: 'Open time', input_html: { value: @workshop.rsvp_opens_at.try(:time).try(:strftime, '%H:%M'), type: :time } .row .col-12.col-md-6 - = f.input :rsvp_close_local_date, label: 'Close date', as: :string, input_html: { data: { value: @workshop.rsvp_closes_at.try(:strftime, '%d/%m/%Y') } } + = f.input :rsvp_close_local_date, label: 'Close date', input_html: { value: @workshop.rsvp_closes_at.try(:strftime, '%Y-%m-%d'), type: :date } .col-12.col-md-6 - = f.input :rsvp_close_local_time, label: 'Close time', as: :string, input_html: { data: { value: @workshop.rsvp_closes_at.try(:time).try(:strftime, '%H:%M') } } + = f.input :rsvp_close_local_time, label: 'Close time', input_html: { value: @workshop.rsvp_closes_at.try(:time).try(:strftime, '%H:%M'), type: :time } diff --git a/spec/controllers/admin/announcements_controller_spec.rb b/spec/controllers/admin/announcements_controller_spec.rb new file mode 100644 index 000000000..7bff3f514 --- /dev/null +++ b/spec/controllers/admin/announcements_controller_spec.rb @@ -0,0 +1,28 @@ +RSpec.describe Admin::AnnouncementsController do + let(:member) { Fabricate(:member) } + let(:announcement) { Fabricate(:announcement) } + + before do + login_as_admin(member) + end + + describe 'GET #new' do + render_views + + it 'renders with a native date input' do + get :new + + expect(response.body).to include('type="date"') + end + end + + describe 'GET #edit' do + render_views + + it 'pre-fills the date value in ISO format' do + get :edit, params: { id: announcement.id } + + expect(response.body).to include("value=\"#{announcement.expires_at.strftime('%Y-%m-%d')}\"") + end + end +end diff --git a/spec/controllers/admin/bans_controller_spec.rb b/spec/controllers/admin/bans_controller_spec.rb new file mode 100644 index 000000000..530285a39 --- /dev/null +++ b/spec/controllers/admin/bans_controller_spec.rb @@ -0,0 +1,25 @@ +RSpec.describe Admin::BansController do + let(:member) { Fabricate(:member) } + let(:admin) { Fabricate(:member) } + + before do + login_as_admin(admin) + end + + describe 'GET #new' do + render_views + + it 'renders with a native date input' do + get :new, params: { member_id: member.id } + + expect(response.body).to include('type="date"') + end + + it 'defaults to approximately one month from today' do + get :new, params: { member_id: member.id } + + expected = (Time.zone.now + 1.month).strftime('%Y-%m-%d') + expect(response.body).to include("value=\"#{expected}\"") + end + end +end diff --git a/spec/controllers/admin/events_controller_spec.rb b/spec/controllers/admin/events_controller_spec.rb index 5f386b5f6..5a1825f82 100644 --- a/spec/controllers/admin/events_controller_spec.rb +++ b/spec/controllers/admin/events_controller_spec.rb @@ -42,4 +42,26 @@ expect(flash[:notice]).to eq('You can\'t be here') end end + + describe 'GET #new' do + render_views + + it 'renders with native date and time inputs' do + get :new + + expect(response.body).to include('type="date"') + expect(response.body).to include('type="time"') + end + end + + describe 'GET #edit' do + render_views + + it 'pre-fills date and time values in ISO format' do + get :edit, params: { id: event.slug } + + expect(response.body).to include("value=\"#{event.date_and_time.strftime('%Y-%m-%d')}\"") + expect(response.body).to include("value=\"#{event.time.strftime('%H:%M')}\"") + end + end end diff --git a/spec/controllers/admin/meetings_controller_spec.rb b/spec/controllers/admin/meetings_controller_spec.rb new file mode 100644 index 000000000..2969eba4f --- /dev/null +++ b/spec/controllers/admin/meetings_controller_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe Admin::MeetingsController do + let(:member) { Fabricate(:member) } + let(:meeting) { Fabricate(:meeting) } + + before do + member.add_role(:organiser, meeting) + login(member) + end + + describe 'GET #new' do + render_views + + it 'renders with native date and time inputs' do + get :new + + expect(response.body).to include('type="date"') + expect(response.body).to include('type="time"') + end + end + + describe 'GET #edit' do + render_views + + it 'pre-fills date and time values in ISO format' do + get :edit, params: { id: meeting.slug } + + expect(response.body).to include("value=\"#{meeting.date_and_time.strftime('%Y-%m-%d')}\"") + expect(response.body).to include("value=\"#{meeting.time.strftime('%H:%M')}\"") + end + end +end diff --git a/spec/controllers/admin/workshops_controller_spec.rb b/spec/controllers/admin/workshops_controller_spec.rb index 431788556..d74de08a7 100644 --- a/spec/controllers/admin/workshops_controller_spec.rb +++ b/spec/controllers/admin/workshops_controller_spec.rb @@ -252,4 +252,45 @@ def assigns(symbol) end end end + + describe 'GET #new' do + render_views + + it 'renders with native date and time inputs for main and RSVP fields' do + get :new + + expect(response.body).to include('type="date"') + expect(response.body).to include('type="time"') + expect(response.body.scan('type="date"').size).to be >= 3 # main date + RSVP open + RSVP close + expect(response.body.scan('type="time"').size).to be >= 3 # main time + RSVP open + RSVP close + end + end + + describe 'GET #edit' do + render_views + + it 'pre-fills main date and time values in ISO format' do + get :edit, params: { id: workshop.id } + + expect(response.body).to include("value=\"#{workshop.date_and_time.strftime('%Y-%m-%d')}\"") + expect(response.body).to include("value=\"#{workshop.time.strftime('%H:%M')}\"") + end + + context 'with RSVP windows set' do + let(:workshop) do + Fabricate(:workshop, + rsvp_opens_at: 1.day.from_now, + rsvp_closes_at: 2.days.from_now) + end + + it 'pre-fills RSVP date and time values in ISO format' do + get :edit, params: { id: workshop.id } + + expect(response.body).to include("value=\"#{workshop.rsvp_opens_at.strftime('%Y-%m-%d')}\"") + expect(response.body).to include("value=\"#{workshop.rsvp_opens_at.strftime('%H:%M')}\"") + expect(response.body).to include("value=\"#{workshop.rsvp_closes_at.strftime('%Y-%m-%d')}\"") + expect(response.body).to include("value=\"#{workshop.rsvp_closes_at.strftime('%H:%M')}\"") + end + end + end end diff --git a/spec/features/admin/announcements_spec.rb b/spec/features/admin/announcements_spec.rb index 154f48511..e7d903313 100644 --- a/spec/features/admin/announcements_spec.rb +++ b/spec/features/admin/announcements_spec.rb @@ -39,6 +39,18 @@ expect(page).to have_text('New event coming up soon! Stay tuned.') expect(page).to have_current_path(admin_announcements_path, ignore_query: true) end + + scenario 'by updating the expires at date' do + announcement = Fabricate(:announcement) + new_date = 2.weeks.from_now.to_date + visit edit_admin_announcement_path(announcement) + fill_in 'Expires at', with: new_date + click_on 'announcement[update]' + + expect(page).to have_text('Announcement successfully updated') + announcement.reload + expect(announcement.expires_at.to_date).to eq(new_date) + end end scenario 'can view all announcements' do