-
-
Notifications
You must be signed in to change notification settings - Fork 486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add expiration to banners #5800
Conversation
10835fb
to
2138b30
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it makes sense to add a test verify the time zone stuff? Something along the lines of:
Set banner => visit page, it shows => change cookies timezone => visit again and confirm that is it gone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set banner => visit page, it shows => change cookies timezone => visit again and confirm that is it gone?
Hmm I was thinking of doing something similar but I don't think the scenario you describe would happen since the expiration time is a fixed point in time, so changing timezone would only affect how it gets displayed. So I did try to test this scenario
Timezone in PT, set banner to N => visit banner edit and see N:00 => change cookies timezone to ET => visit banner edit and see N+3
But was not sure how to do this in capybara/selenium. This is what I tried without success
it "displays expiration time in your current time zone" do
Capybara.using_session("America/Los_Angeles") do
sign_in admin
visit banners_path
click_on "New Banner"
fill_in "Name", with: "name"
fill_in "banner_expires_at", with: "06082024\t0710pm"
click_on "Submit"
visit banners_path
expect(page).to have_text("name")
visit banners_path
within "#banners" do
click_on "Edit", match: :first
end
expect(page).to have_field("banner_expires_at", with: "2024-06-08T19:10")
end
Capybara.using_session("America/New_York") do
sign_in admin
visit banners_path
within "#banners" do
click_on "Edit", match: :first
end
expect(page).to have_field("banner_expires_at", with: "2024-06-08T22:10")
end
end
@active_banner = nil if session[:dismissed_banner] == @active_banner&.id | ||
@active_banner = nil if @active_banner&.expires_at && Time.now.in_time_zone(cookies[:browser_time_zone]) > @active_banner&.expires_at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's extract this to a single method and then test against it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extracted it to Banner#expired
and added a test. Also switched to Time.current
per https://thoughtbot.com/blog/its-about-time-zones.
I also realized that we don't need the timezone conversion here because Time.current
/Time.now
are computed in the backend and >
is timezone aware, so I removed that as well.
params.require(:banner).permit(:active, :content, :name, :expires_at).merge(user: current_user) | ||
.tap { |banner_params| set_expires_at_in_user_time_zone(banner_params) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is doing two things. Can we split the call to conversion out of the banner_params
method? You might take a look at the CaseContactParameters
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this out to a BannerParameters
class
end | ||
|
||
def set_expires_at_in_user_time_zone(banner_params) | ||
banner_params[:expires_at] = banner_params[:expires_at].in_time_zone(cookies[:browser_time_zone]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this method testable? Can we make it testable and then write some tests for it? Maybe this should be a method on the model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the tests for BannerParameters
cover this now. I debated putting it on the model originally but formatting parameters from a request seems like a controller responsibility, so I think having it in the controller/params object makes sense but let me know if you think otherwise
app/views/banners/_form.html.erb
Outdated
@@ -26,6 +26,10 @@ | |||
<%= form.label :active, "Active?", class: 'form-check-label' %> | |||
<span data-reveal-target="item" class="text-danger <%= conditionally_add_hidden_class(form.object.active) %>">Warning: This will replace your current active banner</span> | |||
</div> | |||
<span class="input-style-1"> | |||
<%= form.label :expires_at, "Expires at (optional)" %> | |||
<%= form.datetime_field :expires_at, value: banner.expires_at&.in_time_zone(cookies[:browser_time_zone]), required: false %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic should be in a view helper (and tested).
banner.expires_at&.in_time_zone(cookies[:browser_time_zone])
You might take a look at datetime_local_field. It might eliminate the need for the logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I don't think datetime_local_field helps us here. According to your link, it wraps ActionView::Helpers::FormHelper#datetime_local_field which in turn states that it's only an alias for datetime_field
. According to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local#setting_timezones, timezone aware logic was intentionally left out of this element.
That said, I did try to move this logic to BannerHelper
but ultimately put it in the model. It kind of feels like it would fit best in a presenter type object but might be overkill for now? Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either model or presenter is fine. I agree presenter makes more sense, but if it's just one method does feel like overkill.
app/views/banners/index.html.erb
Outdated
<% if banner.expires_at %> | ||
<%= distance_of_time_in_words(Time.now, banner.expires_at) %> | ||
<% else %> | ||
No | ||
<% end %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A great candidate for a method in the model or view helper (with tests).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this to BannerHelper
which also helped me realize I was missing the case for when the expiration had passed, so I fixed that too
ef26ccb
to
2619a57
Compare
We are choosing to set the timezone in the user's timezone (defined by `cookies[:browser_time_zone]`) by default
form.datetime_field uses html input `datetime-local` under the hood, which does not factor in timezones, so convert it here explicitly
Frontend->Backend: We don't have timezone so we have to attach timezone from browser Backend->Frontend: We have timezone UTC and need to convert it to the browser timezone before displaying
d77fa38
to
599f2e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
What github issue is this PR for, if any?
Resolves #5604
What changed, and why?
Add an optional expiration time to banners.
The timezone will be set to the creator's current timezone.
If a banner is active, but the time is past the expires_at, we will hide the banner.
If the banner is not active, we hide the banner regardless (existing behavior).
Also added displaying the banner on the banners index page
How is this tested? (please write tests!) 💖💪
Note: if you see a flake in your test build in github actions, please post in slack #casa "Flaky test: " :) 💪
Note: We love capybara tests! If you are writing both haml/js and ruby, please try to test your work with tests at every level including system tests like https://github.com/rubyforgood/casa/tree/main/spec/system
Added tests for showing/hiding banner based on
expires_at
. Also added tests for settingexpires_at
in the banner new/edit form.Screenshots please :)
Run your local server and take a screenshot of your work! Try to include the URL of the page as well as the contents of the page.
Feelings gif (optional)
What gif best describes your feeling working on this issue? https://giphy.com/
How to embed: