Skip to content

Commit

Permalink
Add relative date formatting for date/datetime columns
Browse files Browse the repository at this point in the history
  • Loading branch information
hasarindaKI authored and sfnelson committed Mar 1, 2024
1 parent 2e16551 commit 9955b83
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 40 deletions.
80 changes: 70 additions & 10 deletions app/components/koi/tables/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,92 @@ def rendered_value
end

# Formats the value as a date
#
# default format is :admin
# @param format [String] date format, defaults to :admin
# @param relative [Boolean] if true, the date may be(if within 5 days) shown as a relative date
class DateComponent < BodyCellComponent
def initialize(table, record, attribute, format: :admin, **options)
include Koi::DateHelper

def initialize(table, record, attribute, format: :admin, relative: true, **options)
super(table, record, attribute, **options)

@format = format
@format = format
@relative = relative
end

def value
super&.to_date
end

def rendered_value
value.present? ? l(value.to_date, format: @format) : ""
@relative ? relative_time : absolute_time
end

private

def absolute_time
value.present? ? I18n.l(value, format: @format) : ""
end

def relative_time
if value.blank?
""
else
days_ago_in_words(value)&.capitalize || absolute_time
end
end

def default_html_attributes
@relative && value.present? && days_ago_in_words(value).present? ? { title: absolute_time } : {}
end
end

# Formats the value as a datetime
#
# default format is :admin
# @param format [String] datetime format, defaults to :admin
# @param relative [Boolean] if true, the datetime may be(if today) shown as a relative date/time
class DatetimeComponent < BodyCellComponent
def initialize(table, record, attribute, format: :admin, **options)
include ActionView::Helpers::DateHelper

def initialize(table, record, attribute, format: :admin, relative: true, **options)
super(table, record, attribute, **options)

@format = format
@format = format
@relative = relative
end

def value
super&.to_datetime
end

def rendered_value
value.present? ? l(value.to_datetime, format: @format) : ""
@relative ? relative_time : absolute_time
end

private

def absolute_time
value.present? ? I18n.l(value, format: @format) : ""
end

def today?
value.to_date == Date.current
end

def relative_time
return "" if value.blank?

if today?
if value > DateTime.current
"#{distance_of_time_in_words(value, DateTime.current)} from now".capitalize
else
"#{distance_of_time_in_words(value, DateTime.current)} ago".capitalize
end
else
absolute_time
end
end

def default_html_attributes
@relative && today? ? { title: absolute_time } : {}
end
end

Expand Down
46 changes: 18 additions & 28 deletions app/helpers/koi/date_helper.rb
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
# frozen_string_literal: true

# rubocop:disable Naming/MethodName
module Koi
module DateHelper
# @deprecated
def date_format(date, format)
date.strftime format.gsub(/yyyy/, "%Y")
.gsub(/yy/, "%y")
.gsub(/Month/, "%B")
.gsub(/M/, "%b")
.gsub(/mm/, "%m")
.gsub(/m/, "%-m")
.gsub(/Day/, "%A")
.gsub(/D/, "%a")
.gsub(/dd/, "%d")
.gsub(/d/, "%-d")
end

# @deprecated
def date_Month_d_yyyy(date)
date.strftime "%B %-d, %Y"
end

# @deprecated
def date_d_Month_yyyy(date)
date.strftime "%-d %B %Y"
end
# Returns a string representing the number of days ago or from now.
# If the date is not 'recent' returns nil.
def days_ago_in_words(value)
from_time = value.to_time
to_time = Date.current.to_time
distance_in_days = ((to_time - from_time) / (24.0 * 60.0 * 60.0)).round

# @deprecated
def date_d_M_yy(date)
date.strftime "%-d %b %y"
case distance_in_days
when 0
"today"
when 1
"yesterday"
when -1
"tomorrow"
when 2..5
"#{distance_in_days} days ago"
when -5..-2
"#{distance_in_days.abs} days from now"
end
end
end
end
# rubocop:enable Naming/MethodName
50 changes: 49 additions & 1 deletion spec/components/koi/tables/body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,71 @@
end

describe Koi::Tables::Body::DateComponent do
let(:record) { create(:post, published_on: 1.month.ago) }

it "renders column" do
component = described_class.new(table, record, :published_on)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td>#{I18n.l(record.published_on, format: :admin)}</td>
HTML
end

context "when not relative" do
let(:record) { create(:post, published_on: Date.current) }

it "renders column" do
component = described_class.new(table, record, :published_on, relative: false)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td>#{I18n.l(record.published_on, format: :admin)}</td>
HTML
end
end

context "when date is within 5 days" do
let(:record) { create(:post, published_on: 2.days.ago) }

it "renders column" do
component = described_class.new(table, record, :published_on)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td title="#{I18n.l(record.published_on, format: :admin)}">2 days ago</td>
HTML
end
end

context "when future date" do
let(:record) { create(:post, published_on: 3.days.from_now) }

it "renders column" do
component = described_class.new(table, record, :published_on)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td title="#{I18n.l(record.published_on, format: :admin)}">3 days from now</td>
HTML
end
end
end

describe Koi::Tables::Body::DatetimeComponent do
it "renders column" do
component = described_class.new(table, record, :created_at)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td>#{I18n.l(record.created_at, format: :admin)}</td>
<td title="#{I18n.l(record.created_at, format: :admin)}">Less than a minute ago</td>
HTML
end

context "when not relative" do
it "renders column" do
component = described_class.new(table, record, :created_at, relative: false)
rendered = render_inline(component)
expect(rendered).to match_html(<<~HTML)
<td>#{I18n.l(record.created_at, format: :admin)}</td>
HTML
end
end
end

describe Koi::Tables::Body::NumberComponent do
Expand Down
2 changes: 1 addition & 1 deletion spec/components/koi/tables/table_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
expect(table).to match_html(<<~HTML)
<table data-controller="tables--turbo--collection" data-tables--turbo--collection-query-value="" id="table">
<thead><tr><th class="type-datetime">Created at</th></tr></thead>
<tbody><tr><td>#{value}</td></tr></tbody>
<tbody><tr><td title="#{value}">Less than a minute ago</td></tr></tbody>
</table>
HTML
end
Expand Down
27 changes: 27 additions & 0 deletions spec/helpers/koi/date_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Koi::DateHelper do
describe "#days_ago_in_words" do
it "renders today" do
expect(helper.days_ago_in_words(Date.current)).to eq("today")
end

it "renders tomorrow" do
expect(helper.days_ago_in_words(Date.tomorrow)).to eq("tomorrow")
end

it "renders two days from now" do
expect(helper.days_ago_in_words(Date.current + 2.days)).to eq("2 days from now")
end

it "renders two days ago" do
expect(helper.days_ago_in_words(Date.current - 2.days)).to eq("2 days ago")
end

it "returns nil" do
expect(helper.days_ago_in_words(Date.current - 6.days)).to be_nil
end
end
end

0 comments on commit 9955b83

Please sign in to comment.