diff --git a/Gemfile b/Gemfile index 3f50fdb8..6468dcee 100644 --- a/Gemfile +++ b/Gemfile @@ -60,5 +60,5 @@ group :test do end gem "cssbundling-rails", "~> 1.4" - +gem "stimulus-rails" gem "jsbundling-rails", "~> 1.3" diff --git a/Gemfile.lock b/Gemfile.lock index c3bce76e..b57dac4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -410,6 +410,8 @@ GEM standard-performance (1.5.0) lint_roller (~> 1.1) rubocop-performance (~> 1.22.0) + stimulus-rails (1.3.4) + railties (>= 6.0.0) stringio (3.1.1) terser (1.2.4) execjs (>= 0.3.0, < 3) @@ -498,6 +500,7 @@ DEPENDENCIES spring spring-commands-rspec standard + stimulus-rails terser turbo-rails turbolinks (~> 5) diff --git a/app/assets/stylesheets/application.tailwind.css.scss b/app/assets/stylesheets/application.tailwind.css.scss index 2d0e913c..9947c61a 100644 --- a/app/assets/stylesheets/application.tailwind.css.scss +++ b/app/assets/stylesheets/application.tailwind.css.scss @@ -3,3 +3,7 @@ @tailwind base; @tailwind components; @tailwind utilities; + +.active { + @apply border-[3px] border-black border-solid border-b-0 text-black -mb-[3px] bg-white; +} diff --git a/app/javascript/application.js b/app/javascript/application.js index c6cee654..34536749 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -71,3 +71,4 @@ document.addEventListener("DOMContentLoaded", function () { }); }); }); +import "./controllers"; diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js new file mode 100644 index 00000000..d6fe5ebe --- /dev/null +++ b/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus"; + +const application = Application.start(); + +// Configure Stimulus development experience +application.debug = false; +window.Stimulus = application; + +export { application }; diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js new file mode 100644 index 00000000..4c8a6827 --- /dev/null +++ b/app/javascript/controllers/index.js @@ -0,0 +1,8 @@ +// This file is auto-generated by ./bin/rails stimulus:manifest:update +// Run that command whenever you add a new controller or create them with +// ./bin/rails generate stimulus controllerName + +import { application } from "./application"; + +import TabController from "./tab_controller"; +application.register("tab", TabController); diff --git a/app/javascript/controllers/tab_controller.js b/app/javascript/controllers/tab_controller.js new file mode 100644 index 00000000..4ebf3ae8 --- /dev/null +++ b/app/javascript/controllers/tab_controller.js @@ -0,0 +1,20 @@ +import { Controller } from "@hotwired/stimulus"; + +// Connects to data-controller="tab" +export default class extends Controller { + static classes = ["active"]; + static targets = ["day"]; + + connect() {} + + switch_tab() { + this.makeAllTabsInactive(); + this.dayTarget.classList.toggle(this.activeClass); + } + + makeAllTabsInactive() { + document + .querySelectorAll(".tabs .tab") + .forEach((el) => el.classList.remove(this.activeClass)); + } +} diff --git a/app/views/styled_forecasts/_day_tab.html.erb b/app/views/styled_forecasts/_day_tab.html.erb index d98d7e60..bafe73b2 100644 --- a/app/views/styled_forecasts/_day_tab.html.erb +++ b/app/views/styled_forecasts/_day_tab.html.erb @@ -1,19 +1,31 @@ -
- <%= link_to update_styled_forecast_path(day: day), data: { turbo_frame: "day_predictions" } do %> -
- <%= forecast.date == Date.today ? 'Today' : forecast.date.strftime('%A') %> -
-
- <%= forecast.date.strftime("%d %B") %> -
-
- ● -
-
- <%= forecast.air_pollution.label.capitalize %> -
-
- Index <%= forecast.air_pollution.value %>/10 -
- <% end %> -
+<%= tag.div class: "tab py-4 flex-1 #{day} mx-2 px-1 text-center text-gray-400 daqi-low border-b-0 border-l-2 border-r-2 border-t-2 border-gray-400 border-dashed #{day == :today ? "active" : ''}", + data: { + date: forecast.date.to_s, + controller: "tab", + "tab-active-class": "active", + "tab-target": "day" + } do + %> +<%= + link_to update_styled_forecast_path(day: day), + data: { + turbo_frame: "day_predictions", + action: "click->tab#switch_tab" + } do %> +
+ <%= forecast.date == Date.today ? 'Today' : forecast.date.strftime('%A') %> +
+
+ <%= forecast.date.strftime("%d %B") %> +
+
+ ● +
+
+ <%= forecast.air_pollution.label.capitalize %> +
+
+ Index <%= forecast.air_pollution.value %>/10 +
+<% end %> +<% end %> diff --git a/app/views/styled_forecasts/_forecast_tabs.html.erb b/app/views/styled_forecasts/_forecast_tabs.html.erb index fa2f0b39..db9cd0c4 100644 --- a/app/views/styled_forecasts/_forecast_tabs.html.erb +++ b/app/views/styled_forecasts/_forecast_tabs.html.erb @@ -2,7 +2,10 @@
Air pollution
-
+
<%= render "day_tab", forecast: @forecasts.first, day: :today %> <%= render "day_tab", forecast: @forecasts.second, day: :tomorrow %> <%= render "day_tab", forecast: @forecasts.third, day: :day_after_tomorrow %> diff --git a/package.json b/package.json index a64ae9dc..3f77cb2b 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "yarn": "1.22.22" }, "dependencies": { + "@hotwired/stimulus": "^3.2.2", "@hotwired/turbo-rails": "^8.0.10", "autoprefixer": "^10.4.20", "govuk-frontend": "^5.6.0", diff --git a/spec/feature_steps/forecast_steps.rb b/spec/feature_steps/forecast_steps.rb index 14505487..317a32e0 100644 --- a/spec/feature_steps/forecast_steps.rb +++ b/spec/feature_steps/forecast_steps.rb @@ -50,10 +50,16 @@ def and_i_switch_to_the_tab_for_tomorrow switch_to_tab_for(:tomorrow) end + def and_i_switch_to_the_tab_for_day_after_tomorrow + switch_to_tab_for(:day_after_tomorrow) + end + def switch_to_tab_for(day) case day when :tomorrow find(".tab.tomorrow a").click + when :day_after_tomorrow + find(".tab.day_after_tomorrow a").click else raise "day: #{day} not expected" end @@ -105,6 +111,27 @@ def and_i_see_predicted_uv_level_v2 expect_prediction_v2(category: "ultraviolet-rays-uv", value: "Low") end + def then_i_see_that_the_tomorrow_tab_is_active + expect(page).to have_css(".tab.tomorrow.active") + + expect(page).not_to have_css(".tab.today.active") + expect(page).not_to have_css(".tab.day_after_tomorrow.active") + end + + def and_i_see_that_the_today_tab_is_active + expect(page).to have_css(".tab.today.active") + + expect(page).not_to have_css(".tab.tomorrow.active") + expect(page).not_to have_css(".tab.day_after_tomorrow.active") + end + + def then_i_see_that_the_day_after_tomorrow_tab_is_active + expect(page).to have_css(".tab.day_after_tomorrow.active") + + expect(page).not_to have_css(".tab.today.active") + expect(page).not_to have_css(".tab.tomorrow.active") + end + def and_i_see_predicted_uv_level_for_tomorrow expect_styled_prediction(category: :"ultraviolet-rays-uv", level: :moderate) end @@ -117,6 +144,18 @@ def and_i_see_predicted_temperature_level_for_tomorrow expect_styled_prediction(category: :temperature, level: :moderate) end + def and_i_see_predicted_uv_level_for_day_after_tomorrow + expect_styled_prediction(category: :"ultraviolet-rays-uv", level: :high) + end + + def and_i_see_predicted_pollen_level_for_day_after_tomorrow + expect_styled_prediction(category: :pollen, level: :high) + end + + def and_i_see_predicted_temperature_level_for_day_after_tomorrow + expect_styled_prediction(category: :temperature, level: :high) + end + def and_i_see_predicted_pollen_level_v2 expect_prediction_v2(category: :pollen, value: "Low") end @@ -163,6 +202,9 @@ def expect_uv_content_for_level(level) when :moderate expect(page).to have_content("Moderate") expect(page).to have_content(I18n.t("prediction.guidance.ultraviolet_rays_uv.#{level}")) + when :high + expect(page).to have_content("High") + expect(page).to have_content(I18n.t("prediction.guidance.ultraviolet_rays_uv.#{level}")) else raise "unexpected level #{level}" end @@ -173,6 +215,9 @@ def expect_pollen_content_for_level(level) when :moderate expect(page).to have_content("Moderate") expect(page).to have_content(I18n.t("prediction.guidance.pollen.#{level}")) + when :high + expect(page).to have_content("High") + expect(page).to have_content(I18n.t("prediction.guidance.pollen.#{level}")) else raise "unexpected level #{level}" end @@ -182,6 +227,8 @@ def expect_temperature_content_for_level(level) case level when :moderate expect(page).to have_content("9°C - 16°C") + when :high + expect(page).to have_content("27°C - 31°C") else raise "unexpected level #{level}" end diff --git a/spec/features/visitors/view_styled_forecasts_spec.rb b/spec/features/visitors/view_styled_forecasts_spec.rb index af9fe291..f367c562 100644 --- a/spec/features/visitors/view_styled_forecasts_spec.rb +++ b/spec/features/visitors/view_styled_forecasts_spec.rb @@ -24,6 +24,8 @@ visit root_path when_i_select_view_forecasts_v2 then_i_see_the_forecasts_page_v2 + + and_i_see_that_the_today_tab_is_active and_i_see_predicted_air_pollution_status_for_each_day_v2 and_i_see_predicted_uv_level_v2 and_i_see_predicted_pollen_level_v2 @@ -40,9 +42,25 @@ when_i_select_view_forecasts_v2 and_i_switch_to_the_tab_for_tomorrow - # then I see that the _tomorrow_ tab is active + then_i_see_that_the_tomorrow_tab_is_active and_i_see_predicted_uv_level_for_tomorrow and_i_see_predicted_pollen_level_for_tomorrow and_i_see_predicted_temperature_level_for_tomorrow end + + scenario "See detail for day after tomorrow", js: true do + given_a_forecast_for_today + and_a_forecast_for_tomorrow + and_a_forecast_for_the_day_after_tomorrow + and_the_response_from_cercs_api_is_stubbed_accordingly + + visit root_path + when_i_select_view_forecasts_v2 + and_i_switch_to_the_tab_for_day_after_tomorrow + + then_i_see_that_the_day_after_tomorrow_tab_is_active + and_i_see_predicted_uv_level_for_day_after_tomorrow + and_i_see_predicted_pollen_level_for_day_after_tomorrow + and_i_see_predicted_temperature_level_for_day_after_tomorrow + end end diff --git a/yarn.lock b/yarn.lock index 02ce53ae..2aacc04c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -233,6 +233,11 @@ dependencies: levn "^0.4.1" +"@hotwired/stimulus@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608" + integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A== + "@hotwired/turbo-rails@^8.0.10": version "8.0.12" resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-8.0.12.tgz#6f1a2661122c0a2bf717f3bc68b5106638798c89"