Skip to content

Commit

Permalink
Merge pull request #116 from dxw/url-params-3
Browse files Browse the repository at this point in the history
Drive page content with URL parameters
  • Loading branch information
jdudley1123 authored Nov 18, 2024
2 parents 6a6a5be + 80c92f7 commit 14aafd0
Show file tree
Hide file tree
Showing 17 changed files with 75 additions and 117 deletions.
10 changes: 2 additions & 8 deletions app/components/day_tab_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
<%= tag.div class: "tab py-4 flex-1 #{@day} mx-2 px-1 text-center #{classes}",
data: {
date: @forecast.date.to_s,
controller: "tab",
"tab-active-class": "active",
"tab-inactive-class": "inactive",
day: @day,
"tab-target": "dayPrediction",
action: "click->tab#changeTab",
} do
%>
<%= link_to update_forecast_path(day: @day, format: :turbo_stream),
data: {
action: "click->tab#switch_tab click->map#updateMap",
} do %>
<div class="day" data-tab-target="day">
<%= @forecast.date == Date.today ? 'Today' : @forecast.date.strftime('%A') %>
</div>
Expand All @@ -30,4 +25,3 @@
Index <%= @forecast.air_pollution.value %>/10
</div>
<% end %>
<% end %>
5 changes: 3 additions & 2 deletions app/components/day_tab_component.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class DayTabComponent < ViewComponent::Base
def initialize(forecast:, day:)
def initialize(forecast:, day:, active: false)
@forecast = forecast
@day = day
@active = active
end

TAG_COLOURS = {
Expand All @@ -22,7 +23,7 @@ def daqi_indicator_colour_class
end

def classes
if @day == :today
if @active
"active daqi-level-#{@forecast.air_pollution.value}-today"
else
"inactive after-today"
Expand Down
13 changes: 2 additions & 11 deletions app/controllers/forecasts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@ class ForecastsController < ApplicationController
def show
@maptiler_api_key = ENV.fetch("MAPTILER_API_KEY")
@zone = zone
@day = params.fetch("day", "today")
@forecasts = CercForecastService.latest_forecasts_for(zone).data
end

def update
@maptiler_api_key = ENV.fetch("MAPTILER_API_KEY")
forecasts = CercForecastService.latest_forecasts_for(zone).data

@day_forecast = forecast_for_day(params.fetch("day"), forecasts)

respond_to do |format|
format.turbo_stream
end
@day_forecast = forecast_for_day(@day, @forecasts)
end

private
Expand Down
17 changes: 10 additions & 7 deletions app/javascript/controllers/map_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ export default class MapController extends Controller {
.getAttribute("data-maptiler-api-key"),
};

connect() {
this.settings = this.defaultMapSettings;
mapTargetConnected() {
this.updateSettings();
this.createMap();
}

updateSettings() {
const pollutant = this.pollutantSelectorTarget.value;
const date = this.daySelectorTarget.querySelector(".active").dataset.date;
const newSettings = { pollutant: pollutant, date: date };
this.settings = Object.assign({}, this.defaultMapSettings, newSettings);
}

createMap() {
this.map = L.map("map", {
center: this.settings.center,
Expand Down Expand Up @@ -208,11 +215,7 @@ export default class MapController extends Controller {
}

updateMap() {
const pollutant = this.pollutantSelectorTarget.value;
const date = this.daySelectorTarget.querySelector(".active").dataset.date;
const newSettings = { pollutant: pollutant, date: date };
this.settings = Object.assign({}, this.defaultMapSettings, newSettings);

this.updateSettings();
this.updatePollutionLayer();
}

Expand Down
14 changes: 13 additions & 1 deletion app/javascript/controllers/prediction_controller.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import { Controller } from "@hotwired/stimulus";

export default class PredictionController extends Controller {
static targets = ["showButton", "hideButton", "guidance"];
static targets = ["showButton", "hideButton", "guidance", "zoneSelector"];

toggleGuidance() {
this.showButtonTarget.classList.toggle("hidden");
this.hideButtonTarget.classList.toggle("hidden");
this.guidanceTarget.classList.toggle("hidden");
}

changeZone() {
const selectedZone = this.zoneSelectorTarget.value;

// Update the URL with the new zone
const url = new URL(window.location.href);
url.searchParams.set("zone", selectedZone);
window.history.pushState({}, "", url);

// Submit the form to reload the turbo frame
this.zoneSelectorTarget.form.requestSubmit();
}
}
60 changes: 12 additions & 48 deletions app/javascript/controllers/tab_controller.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,23 @@
import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="tab"
export default class extends Controller {
static classes = ["active", "inactive"];
static targets = ["dayPrediction", "day", "daqiValue"];
export default class TabController extends Controller {
static targets = ["daySelector"];

connect() {}

switch_tab() {
this.makeAllTabsInactive();
this.removeDaqiAlertClasses();
changeTab(event) {
const selectedDay = event.currentTarget.dataset.day;

this.addAlertClassIfNotTodayAndHasAirQualityAlert();
this.dayPredictionTarget.classList.toggle(this.activeClass);
this.dayPredictionTarget.classList.toggle(this.inactiveClass);
}

makeAllTabsInactive() {
document.querySelectorAll(".tabs .tab").forEach((el) => {
el.classList.remove(this.activeClass);
el.classList.add(this.inactiveClass);
});
}

addAlertClassIfNotTodayAndHasAirQualityAlert() {
const daqiValue = this.getDaqiValue();
if (this.dayTarget.innerText !== "Today" && daqiValue > 3) {
this.addDaqiAlertClass();
}
}
// Add the new date to the URL
const url = new URL(window.location.href);
url.searchParams.set("day", selectedDay);
window.history.pushState({}, "", url);

addDaqiAlertClass() {
const daqiValue = this.getDaqiValue();
this.dayPredictionTarget.classList.add(
`daqi-alert-after-today-selected-level-${daqiValue}`
);
}

removeDaqiAlertClasses() {
document.querySelectorAll(".tabs .tab").forEach((el) => {
const daqiAlertClassRegex = new RegExp(
"daqi-alert-after-today-selected-level-(\\d{1,2})"
);

const fullClassName = Array.from(el.classList).find((className) =>
className.match(daqiAlertClassRegex)
);

if (fullClassName) {
el.classList.remove(fullClassName);
}
});
}
// Update contents of daySelector
this.daySelectorTarget.value = selectedDay;

getDaqiValue() {
return this.daqiValueTarget.innerText.split("/")[0].split(" ")[1];
// Submit the form to reload the turbo frame
this.daySelectorTarget.form.requestSubmit();
}
}
18 changes: 8 additions & 10 deletions app/views/forecasts/_alert_guidance.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<%= turbo_frame_tag "alert_guidance" do %>
<% if air_pollution_prediction.air_quality_alert %>
<div class="alert-guidance bg-<%= air_pollution_prediction.air_quality_alert.daqi_label.parameterize %>-alert-guidance-panel m-5 p-10">
<p class="font-semibold mb-4">
<%= t("air_quality_alert.#{air_pollution_prediction.air_quality_alert.daqi_level}.guidance.title") %>
</p>
<div class="text-xs">
<%= t("air_quality_alert.#{air_pollution_prediction.air_quality_alert.daqi_level}.guidance.detail_html") %>
</div>
<% if air_pollution_prediction.air_quality_alert %>
<div class="alert-guidance bg-<%= air_pollution_prediction.air_quality_alert.daqi_label.parameterize %>-alert-guidance-panel m-5 p-10">
<p class="font-semibold mb-4">
<%= t("air_quality_alert.#{air_pollution_prediction.air_quality_alert.daqi_level}.guidance.title") %>
</p>
<div class="text-xs">
<%= t("air_quality_alert.#{air_pollution_prediction.air_quality_alert.daqi_level}.guidance.detail_html") %>
</div>
<% end %>
</div>
<% end %>
8 changes: 4 additions & 4 deletions app/views/forecasts/_forecast_tabs.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
data-turbo-prefetch="false"
data-map-target="daySelector"
>
<%= render(DayTabComponent.new(forecast: @forecasts.first, day: :today)) %>
<%= render(DayTabComponent.new(forecast: @forecasts.second, day: :tomorrow)) %>
<%= render(DayTabComponent.new(forecast: @forecasts.third, day: :day_after_tomorrow)) %>
<%= render(DayTabComponent.new(forecast: @forecasts.first, day: 'today', active: @day == 'today')) %>
<%= render(DayTabComponent.new(forecast: @forecasts.second, day: 'tomorrow', active: @day == 'tomorrow')) %>
<%= render(DayTabComponent.new(forecast: @forecasts.third, day: 'day_after_tomorrow', active: @day == 'day_after_tomorrow')) %>
</div>
<%= render partial: "alert_guidance", locals: {air_pollution_prediction: @forecasts.first} %>
<%= render partial: "alert_guidance", locals: {air_pollution_prediction: @day_forecast} %>
</div>
4 changes: 3 additions & 1 deletion app/views/forecasts/_location_selector.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<%= form_tag(false, method: :get) do %>
<%= select_tag :zone,
options_for_select(Zone.all.order(:name).map(&:name), @zone.name),
class: "inline-flex flex-row w-full justify-left gap-x-1.5 rounded-md bg-white px-3 py-2 text-base font-semibold text-gray-500 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
class: "inline-flex flex-row w-full justify-left gap-x-1.5 rounded-md bg-white px-3 py-2 text-base font-semibold text-gray-500 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50",
data: { controller: "prediction", "prediction-target": "zoneSelector", action: "change->prediction#changeZone" }
%>
<%= hidden_field_tag :day, @day, data: { "tab-target": "daySelector" } %>
<% end %>
</div>
12 changes: 5 additions & 7 deletions app/views/forecasts/_predictions.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<%= turbo_frame_tag "day_predictions" do %>
<dl class="predictions p-4">
<%= render(PredictionComponent.new(prediction: forecast.uv)) %>
<%= render(PredictionComponent.new(prediction: forecast.pollen)) if forecast.pollen.valid? %>
<%= render "temperature_prediction", prediction: forecast.temperature %>
</dl>
<% end %>
<dl class="predictions p-4">
<%= render(PredictionComponent.new(prediction: forecast.uv)) %>
<%= render(PredictionComponent.new(prediction: forecast.pollen)) if forecast.pollen.valid? %>
<%= render "temperature_prediction", prediction: forecast.temperature %>
</dl>
6 changes: 3 additions & 3 deletions app/views/forecasts/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
</h2>
</div>

<div data-controller="map">
<turbo-frame id="forecasts" data-controller="map tab">
<%= render partial: "forecasts/location" %>
<%= render partial: "forecasts/forecast_tabs", cerc_forecasts: @forecasts %>
<%= render partial: "forecasts/map" %>
<%= render partial: "forecasts/predictions", locals: { forecast: @forecasts.first } %>
<%= render partial: "forecasts/predictions", locals: { forecast: @day_forecast } %>
<%= render partial: "sharing" %>
</div>
</turbo-frame>
<%= render partial: "learning" %>
<%= render partial: "subscribe" %>
2 changes: 0 additions & 2 deletions app/views/forecasts/update.turbo_stream.erb

This file was deleted.

1 change: 0 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
get "map", to: "map#show"

get :forecast, to: "forecasts#show"
get :update_forecast, to: "forecasts#update"

get :health_advice, to: "pages#health_advice"
get :about, to: "pages#about"
Expand Down
2 changes: 1 addition & 1 deletion spec/components/day_tab_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
describe "classes" do
context "when the day is today" do
let(:component) {
DayTabComponent.new(forecast: FactoryBot.build(:forecast, air_pollution_level: 1), day: :today)
DayTabComponent.new(forecast: FactoryBot.build(:forecast, air_pollution_level: 1), day: :today, active: true)
}

it "returns the classes for today's tab" do
Expand Down
8 changes: 3 additions & 5 deletions spec/controllers/forecasts_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,15 @@

expect(response).to render_template("show")
end
end

describe "GET :update" do
context "when a recognised _day_ parameter is received" do
it "renders the turbo update template" do
allow(CercForecastService).to receive(:latest_forecasts_for).and_return(forecasts)

get :update, params: {day: :today}, format: :turbo_stream
get :show, params: {day: :today}

expect(CercForecastService).to have_received(:latest_forecasts_for).with(southwark)
expect(response).to render_template("forecasts/update")
expect(response).to render_template("show")
end
end

Expand All @@ -58,7 +56,7 @@
allow(CercForecastService).to receive(:latest_forecasts_for).and_return(forecasts)

expect {
get :update, params: {day: :yesterday}
get :show, params: {day: :yesterday}
}.to raise_error(ArgumentError, "Invalid day: yesterday")
end
end
Expand Down
8 changes: 4 additions & 4 deletions spec/features/visitors/view_air_quality_alerts_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
within(".alert-guidance") do
expect_to_see_guidance_for(:moderate)
end
expect(page).to have_css(".tab.tomorrow.daqi-alert-after-today-selected-level-4")
expect(page).not_to have_css(".tab.day_after_tomorrow.daqi-alert-after-today-selected-level-10")
expect(page).to have_css(".tab.tomorrow.active")
expect(page).not_to have_css(".tab.day_after_tomorrow.active")
end
end

Expand All @@ -61,8 +61,8 @@
within(".alert-guidance") do
expect_to_see_guidance_for(:very_high)
end
expect(page).to have_css(".tab.day_after_tomorrow.daqi-alert-after-today-selected-level-10")
expect(page).not_to have_css(".tab.tomorrow.daqi-alert-after-today-selected-level-4")
expect(page).to have_css(".tab.day_after_tomorrow.active")
expect(page).not_to have_css(".tab.tomorrow.active")
end
end
end
4 changes: 2 additions & 2 deletions spec/support/features/forecast_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ def view_forecasts
def switch_to_tab_for(day)
case day
when :tomorrow
find(".tab.tomorrow a").trigger("click")
find(".tab.tomorrow").trigger("click")
when :day_after_tomorrow
find(".tab.day_after_tomorrow a").trigger("click")
find(".tab.day_after_tomorrow").trigger("click")
else
raise "day: #{day} not expected"
end
Expand Down

0 comments on commit 14aafd0

Please sign in to comment.